We're using a Function Import in an EF4 model to populate an existing entity in our Model. The entity in the model has a Key field of Id which we're struggling to map as our stored procedure doesn't return an Id field. I've tried setting the value in the mapping to a literal value of 0 but that fails with an EntityCommandExecutionException and the following exception text.
The data reader is incompatible with the specified 'Candidate'. A member of the type, 'Id', does not have a corresponding column in the data reader with the same name.
Short of modifying the stored procedure to return a dummy Id field can anyone recommend what the best approach is for this as the dummy field option feels very clunky to me.
Many Thanks
If you can't return enough data to fully materialize the entity -- and the Id field is certainly going to be required for that -- then you need to change the return type on the proc to be a complex type instead of an entity.
Use another POCO class with the same structure to receive the results of the stored procedure call, here's an example:
string sp = string.Format("EXEC dbo.spComercialesAsociadosActivos {0}", idComercialPrincipal);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<InfoComercial>(sp);
In this case "InfoComercial" is a POCO class with the same structure as "Comercial", which is tied up to EF code first in the DBContext, then I used this independent class in the viewModel to create a disconnected "Comercial", it's not an ideal solution but will work fine until EF 5 comes with SP support.
Related
We have a db table that has the following columns.
WidgetId (PK)
WidgetName
WidgetCreatedOn
WidgetLastUpdatedOn
We have stored procedures that handle the update/delete/insert on the Widget table.
The Insert stored proc takes just the WidgetName as the parameter e.g.
exec Widget_Insert #WidgetName='Foo Widget'
Then the stored procedure puts the dates in for the WidgetCreatedOn WidgetLastUpdatedOn itself.
The Widget object has the same properties as the table e.g.
WidgetId (Key)
WidgetName
WidgetCreatedOn
WidgetLastUpdatedOn
Is it possible to tell the MapToStoredProcedures to ignore specific properties e.g.
modelBuilder.Entity<Widget>()
.MapToStoredProcedures(s =>
s.Insert(i => i.HasName("Widget_Insert")
.Parameter(a => a.WidgetName, "WidgetName")
.Parameter(a => a.WidgetCreatedOn, **dont map it**)
.Parameter(a => a.WidgetLastUpdatedOn, **dont map it**)));
We are doing Code-First
While there might be a way to manually change the MapToStoredProcedures configuration to do this, I have not uncovered it yet. Having said that, there is a way to accomplish this which I assume is how EF expects you to do things.
In your model mapping, specifying a DatabaseGeneratedOption of Identity or Computed will prevent that property from being sent to the insert proc.
If you think about it, this makes some sense. An insert proc will take as much information from the model as possible to do the insert. But an Identity/Computed property is one for which you're saying the DB will provide the data instead so it won't look to the model for that data.
A couple of things to note with this approach. EF will expect those Identity/Computed fields to come back from the proc so you'll need a select after the insert (filtering on SCOPE_IDENTITY() in sql server). EF also assumes that Identity fields won't come back as null, so those have to be Computed even if you don't intend them to be updated later.
If none of that seems palatable, the way to do this kind of thing in EF5 (and is a bit more flexible) is to override SaveChanges on the context and call the proc when the type is Widget and is EntityState.Added. Or you could throw an exception instead to force devs to call the proc on their own vs using EF's DBSet Add method.
Any properties that don't need to be passed to mapped stored procedures (ever) can be marked as computed. Just add the attribute [DatabaseGenerated(DatabaseGeneratedOption.Computed)] in front of your property definitions. The proc MUST return a result set with all the "computed" values after your procedure runs, or else there will be optimistic concurrency errors. A Select * from where should be fine.
If your classes are generated, you can make a partial class to keep all these attributes safe.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyEfNamespace
{
[MetadataType(typeof(MetaData))]
public partial class Widget
{
public class MetaData
{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.DateTime WidgetCreatedOn;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.DateTime WidgetLastUpdatedOn;
...
}
}
}
I am using EF 4.1, code first and want a property on a customer entity built up of a constant string value and the customerId zero padded to act as a customer reference.
I might be being a bit daft but am struggling to work out how I can achieve this without
A) having to savechanges twice, once to get the Id then set my reference and save again
B) having a partial Customer class that simply provides a getter returning constant + CustomerId.Tostring("000000")
Is this "doable" with code first?
If you can change the database I would make a computed column for this. Thus, you leave it to the database to generate a reference value and it will also be available to other consumers of the database (if any).
Your Customer class will have a property like CustomerReference (string) that maps to the computed column and that is configured to have DatabaseGeneratedOption.Computed which will cause EF to read the value after inserting an object.
I want to use a Money value object in my application. I have found several examples of a Money datatype. But I can't figure out how to use them with EF4. I would like to store each amount as a Decimal/CurrencyCode pair (where currencycode is a string - "USD", "SEK", etc) in the database. I tried creating a complexType but I couldn't get that to work. Is this possible?
It should be definitely possible. Your complex type is just pair of decimal and string property. It is exactly what complex type are used for. Depending on your approach you must do:
Database first:
You will define your database first. Your table will contain money and varchar columns representing your new type. When you update your EDMX model from database it will include it as scalar properties to your entity. You must remove those properties. Then go to model browser and create new complex type. Return back to entity and add complex property of your new complex type. And at the end you must go to entity mapping and map your complex type to those database columns.
Here is basic tutorial from MSDN but from unknown reason they didn't include such elementary details like screenshots. Here is some video from channel9.
Model first:
This is similar to database first but you don't have to deal with database creation and mapping. It will be generated for you.
Code first (EF 4.1):
You must create separate class for your complex type and use it as property in your entity. You should not need to map it by default - mapping should be infered. If it doesn't work you can map complext type either by using ComplextTypeAttribute annotation or by defining mapping in DbModelBuilder.
I can further extend approach you need to use if you provide more details.
We are using ado.net entity framework 4.0 for our database layer and I am a newbie to ado.net entity framework. I have created entity via adding a entity in entity framework. I want to map that entity with stored procedure only not table of the database. Stored procedure will return same column as entity. How it is possible and how i can do that without mapping to table?
Here is a complete walkthrough http://msdn.microsoft.com/en-us/library/cc716679.aspx
Its not possible because an ObjectSet is an IQueryable and mapping an ObjectSet to stored procedure would not give u an IQueryable because stored procedures by their very nature cannot be composed. The best you can do is take the content inside the stored procedure and put into a view and map the view to an ObjectSet which is possible.
You need to create a complex type, not an entity. Open up the model browser and import your stored procedure as a "function import" (your SP must not use #tempTables but you can use #tableVariables instead); in the function import wizard you'll see a "create complex type" button.
The SP becomes a method in the model context and you can use it to get IEnumerable[TheComplexType].
In EF4.1 code-first it's even simpler, you put a [ComplexType] attribute on top of any class and you can use that type as a return type for context.ExecuteStoreQuery[T]. If your properties are named exactly as the returned columns are (and the types line up), the mapping is "magic" - it just works.
We've started using Entity Framework 4 for data access and have come across an issue or perhaps lack of understanding.
Our current system is heavily reliant on Stored Procedures, these procedure contain some necessary business logic so we need to continue to use these when doing Select/Insert/Update/Delete.
The issue we are having is the following:
We've mapped a table to an entity, let's say for example this is a User entity and has the following properties - UserId, FirstName, LastName
Now in our sproc to insert a user we accept FirstName, LastName, CreatedById as parameters.
As our User Entity has no CreatedById we get an error indicating that no property of our Entity can be mapped to the "CreatedById" parameter.
Now one thing we've tried is to manually add a CreatedById scalar property to our Entity, but this results in the issue that there is no Field in our User table in the data source that maps to CreatedById. In general the additional property that we'd like to pass in is not something that is stored.
Now there is potential solution to this in that we can just map the procedures to Function Imports and not bother with using the .AddObject, .DeleteObject, .SaveChanges way of manipulating our objects but that doesn't feel like the way to go about it.
that's a good question. There are few options i can tell u.
instead of mapping the entity to the table, map it a view and have the view return CreatedById and then your problem would be solved.
Second option is to create overloaded stored procedure that takes only FirstName, LastName and calls the actual stored procedure with a default value for CreatedById. You can create overloads at the database layer or create it in the model in the ssdl layer which supports inline stored procedure.
exec myproc #firstName,#LastName,null