Entity Framework - using stored proc and mapping properties - c#

I have my framework setup with code first with a BaseEntity type that simply contains Id and a Name properties (all my db tables have at least these two fields). The problem is that the db was written before we implemented EF so many of the columnnames in the db do not match this nice Id/Name convention (for example there might be CustomerId and CustomerName etc). Now as far basic CRUD operations go this works fine because I simply do this in my mappings:
this.HasKey(t => t.Id).Property(t => t.Id).HasColumnName("CustomerId");
and it correctly maps from one to another and all is good
However, we also have some complex database logic that can only be encapsulated in stored procedures so in my ObjectContext I have a generic method for invoking sprocs that returns IList and allows you to pass in the name of the proc to invoke and any params it requires, it then goes to the underlying Database object on the ObjectContext to make the call. This works great for classes where the property names in the poco match those in the db, but if they do not, it ignores any mapping I have setup for that object (see above) and I get an error like this:
The data reader is incompatible with the specified 'SomeNamespace.Customer'.
A member of the type, 'Id', does not have a corresponding column in the data
reader with the same name.
Is there any clean way to work around this or to properly instruct it to map it correctly on the underlying datareader?
thanks

Related

Using AutoMapper with EF6 DbFirst and Stored Procedure (complex types)

I am using Entity Framework 6 DBFirst, MVC5 and AutoMapper.
I have 2 tables, Customers and CustomerContacts
For each class I have in Entity Framework EDMX (auto-generated) I have a Model class with the exact same properties. i.e. Customer => Model.Customer, CustomerContact => Model.CustomerContact. This is why I use AutoMapper.
Question 1: Since my Customer_Get stored procedure returns an auto-generated complex type (Customer_Get_Result) would most people make an additional model class for this also? (Model.Customer_Get_Result.cs) Or are all of the properties supposed to get combined adding everything to Model.Customer?
Question 2: Is the way I am handling mapping for Customer Contacts below correct? Mostly every property in Model.Customer is exactly the same as the AutoGenerated EF6 DBFirst file except for this which I placed in Model.Customer:
public List<CustomerContact> Contacts { get; set; }
In the end I want to be able to use Customer.Contacts to automatically get a list of all that Customer's contacts
In my AutoMapper I am trying to do something like this but don't think this is correct:
CreateMap<Customer, Model.Customer>()
.ForMember(dest => dest.Contacts, opt => opt.MapFrom(src => src.CustomerContact));
//map for customer getlist stored proc which will be returning several fields
//such as TotalCount, RowNumber, fields from a bunch of other tables
CreateMap<Customer_Get_Result, Model.Customer>();
For a stored procedure's complex type (Customer_Get_Result) would most
people make an additional model class for this also?
If it is exactly same properties as Customer, then I probably wouldn't create a model just for it, and just map it to the existing model.
Although it depends on what you are doing with this Model class, and whether the use case for the data mapped from the entity is any different than the data mapped from the stored procedure. Model's are just a fancy term for POCO. Models are often one of two things. A simplification of the entity, that is closer to a POCO than the EF entity is; such as DTO's you might use between your business layer and database layer. Or it is a specialization for a particular context, such as a ViewModel that has only properties needed for a particular view and often includes things like data annotations that are UI specific.
It depends alot on how your application is layered and what part of the application is retrieving data, and what it plans to do with that data. That said, I'd probably start with just using the same Model and see if I feel a need to rafactor later(but you'll still need 2 mappings, one from SP_Complex_Type -> Model, and one Entity -> Model).
Looks like your DB/EF model only has a single related contact from Customer.CustomerContact, but your model has a one-to-many relationship Model.Customer.Contacts. I'm basing this only on the plurality of the property name since you didn't give us any declarations of your entity. Either way there's a mismatch on the relationship your EF entity supports versus the relationship your Model supports. There's alot of different things you can do here with AutoMapper, but you can't make that decision until you figure why one has a list of related contacts, and the other only has a single related contact.
CreateMap<Customer, Model.Customer>()
.ForMember(dest => dest.Contacts, opt => opt.MapFrom(src => src.CustomerContact));
When mapping a list to a list, and the properties are named differently, then the above is exactly what you would do. Additionally if the types in each list are different, then you need to make sure your previously declared a map for those types as well. For example, if you are going from List<CustomerContactEntity> to List<CustomerContactModel> then you need to have already done a CreateMap<CustomerContactEntity,CustomerContactModel> to tell AutoMapper it can convert these types. This way as it encounters each item in the list, it will see that it has a mapping for that child type.

How can I denormalize my clr entity, but keep my db tables normalized?

I have these two related tables Client (ClientId, Name) and ClientDescription (ClientDescriptionId, (FK) ClientId, Description). That is to say each Client can have many associated descriptions. Now, when displaying the a list of ClientDescriptions, I also need to know what the Name of it's associated Client is.
Now you'll probably say that I allready have this information, since I can simply follow my navigation property back to the associated Client and use its Name. I can't do that because I'm autogenerating a grid in Ria services, and this just gives me a count for navigation properties, and I haven't found a way to flatten this down in my metadata file. Hence why I want a property.
The whole idea is that I want to be able to add a new field to my database, update my entity classes from the database and regenerate my domain service, and the new field should just pop up in my grid. I shouldn't have to update my xaml just because my database happen to have an extra field.
So, what I would like to do is add a ClientName field to the entity (clr object), but keep my database clean (no such denormalization in the db).
So, I generated my edmx, and added a new property named ClientName. Set it to StoreGeneratedPattern.Computed, and compiled. I then get a nasty little error
Error 3004: Problem in mapping fragments starting at line NN: No mapping specified for properties (etc..)
The solution apparently is to generate my database from my edmx. (Or that's what answers to questions about that error seems to yield.) But this generates an actual DB-field, which I don't want, so that answer doesn't apply to my case.
So my question is: How can I denormalize my clr entity, but keep my db tables normalized?
Edit: I guess this question can be generalized a bit. The issue would be the same if ClientDescription contained a few numeric fields that I wanted to do some calculations on, and I wanted the result available as a field and the algorithm should be in c# rather than in my database.
To answer your more generalized question:
Entities are generated by the Entity Framework with a partial keyword.
This means that the code of an entity can be split in multiple source files in the same namespace and assembly. One will contain the generated code from the Entity Framework, the other will contain custom properties and methods.
If for example, your entity has the database fields Price and Amount you could add a property in the partial class TotalPrice which would return Price * Amount.
Then the algorithm will be C# and your database won't know about the extra property.

Entity Framework Design - Multiple "Views" for the data

I have a design question related to Entity Framework entities.
I have created the following entity:
public class SomeEntity {
// full review details here
}
This entity has as an example 30 columns. When I need to create a new entity this works great. I have all of the required fields in order to insert into the database.
I have a few places in my app where I need to display some tabular data with some of the fields from SomeEntity, but I don't need all 30 columns, maybe only 2 or 3 columns.
Do I create an entirely new entity that has only the fields I need (which maps to the same table as SomeEntity, but only retrieves the column I want?)
Or does it make more sense to create a domain class (like PartialEntity) and write a query like this:
var partialObjects = from e in db.SomeEntities
select new PartialEntity { Column1 = e.Column1, Column2 = e.Column2 };
I am not sure what the appropriate way to do this type of thing. Is it a bad idea to have two entities that map to the same table/columns? I would never actually need the ability to create a PartialEntity and save it to the database, because it wouldn't have all of the fields that are required.
Your first approach is not possible. EF doesn't support multiple entities mapped to the same table (except some special cases like TPH inheritance or table splitting).
The second case is common scenario. You will create view model for your UI and either project your entity to view model directly in query (it will pass from DB only columns you project) or you will query whole entity and make conversion to view model in your application code (for example by AutoMapper as #Fernando mentioned).
If you are using EDMX file for mapping (I guess you don't because you mentioned ef-code-first) you can use third approach which takes part from both mentioned approaches. That approach defines QueryView - it is EF based view on the mapped entity which behaves as a new read only entity. Generally it is reusable projection stored directly in mapping.
What you proposed as a first solution is the "View model paradigm", where you create a class for the sole purpose of being the model of a view to retrieve data and then map it to the model class. You can use AutoMapper to map the values. Here's an article on how to apply this.
You could create a generic property filter method that takes in an object instance, and you pass in a string array of column names, and this method would return a dynamic object with only the columns you want.
I think it would add unnecessary complexity to your model to add a second entity based on the same data structure. I honestly don't see the problem in having a single entity for updating\editing\viewing. If you insist on separating the access to SomeEntity, you could have a database view: i.e. SomeEntityView, and create a separate entity based on that.

Dynamically loading SQL tables in Entity Framework

I need to dynamically access some SQL tables hopefully using the Entity Framework. Here's some pseudo code:
var Account = DB.Accounts.SingleOrDefault(x => x.ID == 12345);
which will return me an Account object and this contains some fields called "PREFIX", "CAMPAIGN ID" and further information about the accounts are stored in separate SQL tables with the naming convention of PREFIX_CAMPAIGNID_MAIN.
The tables all have the same fields so I was thinking of creating a new Entity that isn't mapped anywhere and then dynamically loading it, like so:
var STA01_MAIN = new MyAccount(); // my "un-mapped" entity
DB.LoadTable('STA01_MAIN').LoadInto(STA01_MAIN);
I can now get anything about the STA01_MAIN account: STA01_MAIN.AccountId.
So my question is: how do I access these tables using the Entity Framework?
I don't think EF has a LoadTable and LoadInto method, but ObjectOntext.ExecuteStoreQuery might be what you're looking for:
http://msdn.microsoft.com/en-us/library/dd487208.aspx
This should let you execute an arbitrary query against your database, and then map the results to an arbitrary type that you specify (even if it's not otherwise mapped in EF).
It goes without saying that you would be responsible for putting together a query that supplied the necessary columns for mapping into the destination type, and also adjusting said query when this type changes.
Here's some further discussion concerning its usage
http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/44cf5582-63f8-4f81-8029-7b43469c028d/
Have you considered mapping all of these tables (with the identical columns) into an inheritance relationship in EF, and then querying them as
db.BaseTypes.OfType<SpecificType>().Where(/*.....*/);

Entity Framework: Mapping sproc results to existing EF Entity

I am trying to use EF with an existing DB. I brought in a Client table into my data model and let EF create a Client entity. I have a sproc, GetClientSearch, that only returns 5 out of the 15 columns from the Client table becuase that is all that is needed for that call.
Here's what I've done so far:
Added the sproc to Function Imports and set the proc to map to the Client entity.
When I execute the proc through the Context, I get "The data reader is incompatible with the specified 'GAINABSModel.Client'. A member of the type, 'MiddleInitial', does not have a corresponding column in the data reader with the same name." exception. (MiddleInitial is not one of the columns returned in the proc)
I know that I can create a new entity that maps to the proc, but I don't want to do that for every proc I have to import into my model.
Given that the DB is currently in use in production, changing stored procs to map to my current entities may not be an option.
Currently using EF 4 and VS 2010.
So, is there a way to map the results of the sproc to the Client entity, even though the columns returned are not 1:1 with the properties of the EF entity?
Yep, one of my many pain points in EF.
If you can't modify the SP's, your best bet might be to create "wrapper" SP's on top of the existing SP's.
In other words, EF-serving SP's that call into the existing ones, and return NULL for the columns you don't need, but are required for the entity.
Of course the better option would be to create the entities properly.
Another option is to use ObjectContext.Translate<T>, which basically performs a L-R between the SPROC results and the entity you supply.
If the result set doesn't contain the field, then the property on the object will be null.
Which is probably what you want.
Am running into the same Issues. Suppose i have UserEntity created out of the User Table and have 3 procedures.
AuthenticateUser - returns 4 columns from the user table after authentication
RetriveUser - Returns 10 columns from the user table
GetUserName - return UserID and UserName only for dropdown purpose.
If we create different entities for each of the different SP. It would result in bad design because of duplication.
I have no other way of using same entity for all these SP's.
Overall, i don't recommend entity framework atleast for legacy applications in production.(where you can not update your Sp's also.)

Categories