LINQ and web service cannot return anonymous types, and you cannot construct an object in a query? - asp.net

Web services cannot return an anonymous type.
If you are building a LINQ query using classes through a datacontext... you cannot construct instances of those classes in a query.
Why would I want to do this? Say I want to join three "tables" or sets of objects. I have three items with a foreign key to each other. And say the lowest, most detailed of these was represented by a class that had fields from the other two to represent the data from those. In my LINQ query I would want to return a list of the lowest, most detailed class. This is one way I have decided to "join some tables together" and return data from each of them via LINQ to SQL via a WebService. This may be bad practice. I certainly do not like adding the additional properties to the lowest level class.
Consider something like this... (please ignore the naming conventions, they are driven by internal consideration) also for some reason I need to instantiate an anonymous type for the join... I don't know why that is... if I do not do it this way I get an error...
from su in _dataContext.GetTable<StateUpdate>()
join sfs in _dataContext.GetTable<SystemFacetState>()
on new { su.lngSystemFacetState } equals new { lngSystemFacetState = sfs.lngSystemFacetState }
join sf in _dataContext.GetTable<SystemFacet>()
on new { sfs.lngSystemFacet } equals new { lngSystemFacet = sf.lngSystemFacet }
join s in _dataContext.GetTable<System>()
on new { sf.lngSystem } equals new {lngSystem = s.lngSystem}
select new
{
lngStateUpdate = su.lngStateUpdate,
strSystemFacet = sf.strSystemFacet,
strSystemFacetState = sfs.strSystemFacetState,
dtmStateUpdate = su.dtmStateUpdate,
dtmEndTime = su.dtmEndTime,
lngDuration = su.lngDuration,
strSystem = s.strSystem
}
).ToList();
Notice I have to build the anonymous type which is composed of pieces of each type. Then I have to do something like this... (convert it to a known type for transport via the web service)
result = new List<StateUpdate>(from a in qr select(new StateUpdate
{
lngStateUpdate = a.lngStateUpdate,
strSystemFacet = a.strSystemFacet,
strSystemFacetState = a.strSystemFacetState,
dtmStateUpdate = a.dtmStateUpdate,
dtmEndTime = a.dtmEndTime,
lngDuration = a.lngDuration,
strSystem = a.strSystem
}));
It is just awful. And perhaps I have created an awful mess. If I am way way off track here please guide me to the light. I feel I am missing something fundamental here when I am adding all these "unmapped" properties to the StateUpdate class.
I hope someone can see what I am doing here so I can get a better way to do it.

You can create a 'dto' class which just contains the properties you need to return and populate it instead of the anonymous object:
public class Result
{
public string lngStateUpdate
{
get;
set;
}
... // other properties
}
then use it like this:
from su in _dataContext.GetTable<StateUpdate>()
...
select new Result
{
lngStateUpdate = su.lngStateUpdate,
... // other properties
}
Nitpick note - please ditch the Hungarian notation and camel casing for properties :)

I think the answer is to create another object to serve as a DTO. This object would not be mapped to the data context and can contain fields that cross the mapped objects. This solves the problems of repetitive properties in the mapped objects, and allows for instantiation of the DTO class in the query as it is not mapped.
FYI: with respect to the problem with the join- I revisited that and I think I may have had the inner and outer components of the join switched around before.

Related

Breeze: How can I create a GUID key for new entities on the client?

Using Breeze, what is the simplest way to populate a GUID key when an entity is created?
I'll assume that your entity is configured such that the client is responsible for setting the Guid key for new entities. That's the default for the Guid key of an Entity Framework Code First entity; it is as if the key property were adorned with [DatabaseGenerated(DatabaseGeneratedOption.None)]
The obvious approach is to set the key after creating the entity and before adding it to the manager, e.g.:
function createFoo() {
var foo = fooType.createEntity();
foo.id(breeze.core.getUuid()); // Knockout implementation
manager.addEntity(foo);
}
This may be all you ever need.
On the other hand, you may find that you're creating new Foos in many places and for some strange reason you can't use the createFoo function. You certainly don't want to repeat that code.
You can extend the Foo entity type with id-setting behavior after which you'd be able to write:
function createFoo() {
var foo = fooType.createEntity(); // foo.id is set for you
manager.addEntity(foo);
}
There are two approaches to consider - custom constructor and type initializer; both are described in "Extending Entities"
Constructor
You can initialize the key inside a custom constructor. Breeze calls the constructor both when you create the entity and when it materializes a queried entity. Breeze will replace the initial key value when materializing.
Here's an example that assumes the Knockout model library.
function Foo() {
foo.id(breeze.core.getUuid()); // using KO
}
// one way to get the MetadataStore
var store = manager.metadataStore;
// register the ctor with the Foo type
store.registerEntityTypeCtor("Foo", Foo);
Pretty simple. The only downside is that Breeze will generate a Guid every time it makes an entity, whether creating a new one or materializing one from a query. It's wasted effort during materialization but so what? Well, I suppose that might become a performance issue although I wouldn't assume so until I had measured it.
Initializer
Suppose you measured and the repeated Guid generation is a serious problem (really?). You could set the key in a type initializer instead and only call the Guid generator when creating a new entity.
Breeze calls a type initializer after the entity has been created or materialized from query just before returning that entity to the application. Clearly you don't want to overwrite a materialized key from the database so you'll test the key value to make sure it's not real (i.e. to make sure you're fixing a created entity) before assigning it. Here's an example.
function fooInitializer(foo) {
var emptyGuid = "00000000-0000-0000-0000-000000000000";
if (foo.id() !=== emptyGuid) {
foo.id(breeze.core.getUuid());
}
}
var store = manager.metadataStore;
// register the initializer; no ctor in this example
store.registerEntityTypeCtor("Foo", function(){}, fooInitializer);
Assuming you have a Guid surrogate Key on all your entities like we have in our case, you could code a createInstance factory that does the following in a very generic approach:
function createInstance(breezeEntityManager, typeName) {
var keyProperty = breezeEntityManager.metadataStore.getEntityType(typeName, false).dataProperties.filter(function (p) {
return p.isPartOfKey;
})[0];
var config = {};
config[keyProperty.name] = breeze.core.getUuid();
return breezeEntityManager.createEntity(typeName, config);
}
This way, you won't have to create an initializer for all your entities.

different hashtable cacheItem with similar data values or separate cacheItems for each data value – which is an efficient approach?

I have broadly two different classes of data caching requirements based on data size:
1) very small data (2-30 characters) – this includes such things as the type code for a given entityId. The system is based upon the concept of parent-child entity hierarchy and actions are authorized against values that are built in combination with entity type code. Caching these type codes for different entities saves time on db fetch.
2) medium/Large data – This is general data like products description and pages.
I'm confused as to which approach is better suited for first class of data.
I can cache it like this:
HttpRuntime.Cache.Insert("typeCode" + entityId, entityTypeCode);
or like this:
Dictionary<int, string> etCodes =
(Dictionary<int, string>)HttpRuntime.Cache["typeCode"];
etCodes[entityId] = entityTypeCode;
Clearly, In the second approach, I'm saving on unnecessary cache items for each entityId.
or, having Cache object populated with several items of such small size is okay.
Which of these approachs is good in terms of performance and overhead?
Personally I would take your second approach of one single object and use a custom object instead of a Dictionary.
This would enable me to later control more aspects like expiration of items within the object or changing the implementation.
I would do it similar to this:
public class MyCacheObject
{
public static MyCacheObject
{
get
{
// ...Omitted locking here for simplification...
var o = HttpRuntime.Cache["MyCacheObject] as MyCacheObject;
if ( o = null )
{
o = new MyCacheObject();
HttpRuntime.Cache["MyCacheObject] = o;
}
return o;
}
}
public object GetEntity( string id, string code )
{
// ...
}
public void SetEntity( object entity, string id, string code )
{
// ...
}
// ...
}
If you have a custome base class for the entities, the GetEntity and SetEntity methods could be optimized further.

Returing multiple Model objects from LINQ Joins

I am using ASP.NET MVC framework and accessing DB records with Entities.
I am doing some joins like this:
public IQueryable<...> GetThem()
{
var ords = from o in db.Orders
join c in db.Categories on o.CategoryID equals c.ID
select new {Order=o, Category=c};
return ords;
}
I need to use/pass 'ords' from one function to other in a strongly-typed manner.
(I will be doing this kind of joins in multiple places.)
What is the best way to do this?
Do I need create a new class containing both returned vals for every join I do?
Eg: public class OrderAndCategory { public Order; public Category; } in this case.
Is there any simpler way?
Thanks!
The class representing the data in ords is strongly typed, it is generated by the compiler. You could run into problems though if the compiler generates different classes for different instances of the query, but with the same types. You'd have to check that. If this is the case, you'll have to create classes for each different query, or use the class Tuple<Targs...> instead.

ASP.Net Entity Framework Repository & Linq

My scenario:
This is an ASP.NET 4.0 web app programmed via C#
I implement a repository pattern. My repositorys all share the same ObjectContext, which is stored in httpContext.Items. Each repository creates a new ObjectSet of type E. Heres some code from my repository:
public class Repository<E> : IRepository<E>, IDisposable
where E : class
{
private DataModelContainer _context = ContextHelper<DataModelContainer>.GetCurrentContext();
private IObjectSet<E> _objectSet;
private IObjectSet<E> objectSet
{
get
{
if (_objectSet == null)
{
_objectSet = this._context.CreateObjectSet<E>();
}
return _objectSet;
}
}
public IQueryable<E> GetQuery()
{
return objectSet;
}
Lets say I have 2 repositorys, 1 for states and 1 for countrys and want to create a linq query against both. Note that I use POCO classes with the entity framework. State and Country are 2 of these POCO classes.
Repository stateRepo = new Repository<State>();
Repository countryRepo = new Repository<Country>();
IEnumerable<State> states = (from s in _stateRepo.GetQuery()
join c in _countryRepo.GetQuery() on s.countryID equals c.countryID
select s).ToList();
Debug.WriteLine(states.First().Country.country)
essentially, I want to retrieve the state and the related country entity. The query only returns the state data... and I get a null argument exception on the Debug.WriteLine
LazyLoading is disabled in my .edmx... thats the way I want it.
You're doing a join without retrieving anything from it. There are multiple solutions to your problem:
Use Include to load the dependent entities: from s in ((ObjectSet<State>) _stateRepo.GetQuery).Include("Country"). The problem with this approach is that you should expose the ObjectSet directly rather than as a IQueryable if you want to avoid casting.
Use context.LoadProperty(states.First(), s => s.Country) to explicitly load the Country from the database for a given state.
Select both entities in the query: from s in ... join c ... select new { s, c }. You won't be able to access directly the state's Country property but you have it in the anonymous type.
Enable lazy loading.
Your repository implementation is very similar to mine, especially the way you are storing the ObjectContext. It works fine for me, so I don't think it's a conceptual problem.
Try using a static objectcontext (no wrapper) just to see if that fixes the problem. Perhaps there is a bug in your ContextHelper which causes your context to get disposed and recreated.

Should I return IList or List to the Controller in MVC?

What is difference to the controller that gets the return with repect to rendering the List?
In Linq dataContext:
public IList<Response> GetResponses(int ID)
{
var responses = from r in this.Responses where r.ID == ID orderby r.Date select r;
return responses.ToList();
}
OR
public List<Response> GetResponses(int ID)
{
var responses = from r in this.Responses where r.ID == ID orderby r.Date select r;
return responses.ToList();
}
I doubt there's much difference to the controller but you should probably try to reveal as little information as possible about the private data of your classes. This means exposing interfaces rather than concrete types and using the interface that exposes the minimum amount of information the client will need to operate on the data.
If the controller only needs an IEnumerable<Response> then you should consider making that the return type of GetResponses.
The difference is that the controller won't need to be updated if you change your List implementation if you use the IList interface. It's probably not that big of a deal unless you are planning to make your library available to others. In that case the abstraction is probably justified as you won't be the only one having to update your code if you make the change.
Consider returning an array, consider accepting IEnumerable as a parameter.

Resources