Entity Framework with POCO Template and FKs in Model - Null Ref Exception - entity-framework

I'm using Entity Framework 4 with the POCO code generation template from Microsoft downloaded from the Visual Studio gallery. I am also leaving the default option to "Include foreign keys in model" selected when generating the EF model from the database.
I've been able to reproduce this problem with a very simple model, only two tables/classes in an optional one-to-many relationship. In this case, I'm using an Address and a Person. A Person can have one or zero addresses, and an Address can have zero to many People.
The tables look like this:
CREATE TABLE [dbo].[Person](
[PersonID] [uniqueidentifier] NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[AddressID] [uniqueidentifier] NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ([PersonID] ASC )
CREATE TABLE [dbo].[Address](
[AddressID] [uniqueidentifier] NOT NULL,
[Street1] [nvarchar](50) NOT NULL,
[Street2] [nvarchar](50) NULL,
[City] [nvarchar](50) NOT NULL,
[State] [char](2) NOT NULL,
[Country] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED ([AddressID] ASC)
ALTER TABLE [dbo].[Person] WITH CHECK ADD CONSTRAINT [FK_Person_Address]
FOREIGN KEY([AddressID])
REFERENCES [dbo].[Address] ([AddressID])
When I try to create an Address object and add it to an existing Person object pulled from the database, I get a null reference exception:
TestPOCOEntities ctx = new TestPOCOEntities();
var person = ctx.People.FirstOrDefault(p => p.PersonID == new Guid("58AD37B4-1EBE-4649-940C-A141732C9901"));
var addr = new Address {AddressID = Guid.NewGuid(), Street1 = "123 Main St"};
person.Address = addr; // This line throws the exception
ctx.SaveChanges();
Digging into the call stack, the exception isn't being thrown from my code, or even the template-generated code, but inside the runtime dynamic proxy for the Person class in the AddressID setter. (Specifically, the System.Data.Objects.EntityEntry.FixupEntityReferenceByForeignKey(EntityReference reference) method.)
This exception does not occur if I use the default EF code generation instead of the POCO template. It also does not occur if I use the POCO template but uncheck the "Include foreign keys in model" checkbox when generating the model from the database.
I can get the error to go away if I add the following:
var addr = new Address {AddressID = Guid.NewGuid(), Street1 = "123 Main St"};
ctx.Addresses.AddObject(addr); // Adding this line...
person.Address = addr; // Means no more exception here!
I don't see why the combination of using the POCO template and including foreign keys in the model should require this kind of code change when interacting with my persistent objects. Is this a known bug? Am I missing something? Is this by design for some reason?

this is a potential bug of EF, usually then refresh a created entity (resave changes with new data) solution:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/832af255-d1c2-41d5-9e95-9cdf3b15bb57
the cheat is add the entity to the collection context first
second assign to the father entity
third, savechanges normally!
enjoy

Related

EntityFramework - many-to-many reference in the DB without a backreference in the model

In my application users can define Parameters, and then create SlideSets based on a grouping of parameters.
I am using code-first Entity Framework 5.0 and I have the following model:
class SlideSet {
public ICollection<Parameter> Parameter
}
class Parameter {}
A parameter might be used by many slidesets or none at all. However, in my domain a parameter has no need to reference a SlideSet, they are in separate bounded contexts (both SlideSet and Parameter are Aggregate Roots). As such, I don't want to put a reference from Parameter to SlideSet.
The table model (I don't care about table/column names) that I want is
Table SlideSet
Table Param
Table SlideSetParam
FK_SlideSet
FK_Param
I know I could model this by introducing a ParameterGroup entity or a Param.SlideSets collection, but it would exist solely for ORM mapping purposes (and cause serialization issues). Is there any other way to tell EF to generate this table model from my entities?
This should make you a Parameter w/o a navigation property:
modelBuilder.Entity<SlideSet>()
.HasMany(x => x.Parameters)
.WithRequired();
EDIT:
Based on the comment - that should be all together similar. This seems to work nicely what you're trying to do....
modelBuilder.Entity<SlideSet>()
.HasMany(x => x.Parameters)
.WithMany();
...and you can use it either way:
var slideset = new SlideSet { Parameters = new []
{
new Parameter{},
new Parameter{},
new Parameter{},
new Parameter{},
}
};
var slideset2 = new SlideSet { };
db.SlideSets.Add(slideset);
db.SaveChanges();
var slidesets = db.SlideSets.ToList();
var parameters = db.Parameters.ToList();
Console.WriteLine("");
db.SlideSets.Add(slideset2);
db.SaveChanges();
slidesets = db.SlideSets.ToList();
parameters = db.Parameters.ToList();
Console.WriteLine("");
...and the SQL:
CREATE TABLE [dbo].[Parameters] (
[ParameterID] [int] NOT NULL IDENTITY,
CONSTRAINT [PK_dbo.Parameters] PRIMARY KEY ([ParameterID])
)
CREATE TABLE [dbo].[SlideSets] (
[SlideSetID] [int] NOT NULL IDENTITY,
CONSTRAINT [PK_dbo.SlideSets] PRIMARY KEY ([SlideSetID])
)
CREATE TABLE [dbo].[SlideSetParameters] (
[SlideSet_SlideSetID] [int] NOT NULL,
[Parameter_ParameterID] [int] NOT NULL,
CONSTRAINT [PK_dbo.SlideSetParameters] PRIMARY KEY ([SlideSet_SlideSetID], [Parameter_ParameterID])
)
CREATE INDEX [IX_SlideSet_SlideSetID] ON [dbo].[SlideSetParameters]([SlideSet_SlideSetID])
CREATE INDEX [IX_Parameter_ParameterID] ON [dbo].[SlideSetParameters]([Parameter_ParameterID])
ALTER TABLE [dbo].[SlideSetParameters] ADD CONSTRAINT [FK_dbo.SlideSetParameters_dbo.SlideSets_SlideSet_SlideSetID] FOREIGN KEY ([SlideSet_SlideSetID]) REFERENCES [dbo].[SlideSets] ([SlideSetID]) ON DELETE CASCADE
ALTER TABLE [dbo].[SlideSetParameters] ADD CONSTRAINT [FK_dbo.SlideSetParameters_dbo.Parameters_Parameter_ParameterID] FOREIGN KEY ([Parameter_ParameterID]) REFERENCES [dbo].[Parameters] ([ParameterID]) ON DELETE CASCADE
...this makes the original tables practically 'agnostic' of the relationships (many-to-many) - while index table is automatically generated in the background.
You can also further customize that and make your own SlideSetParam (e.g. if you'd want to add additional fields there) with pretty much the same layout - just Parameters would have to point to that instead.

Composite-primary key issue in entity framework code first

I have an issue in entity framework code first, three table in database as follows:
CREATE TABLE [Food](
PK [FoodId] [int] NOT NULL,
[FoodName] [varchar](50) NULL)
CREATE TABLE [Fruit](
PK [FruitId] [int] NOT NULL,
[FruitName] [varchar](50) NULL)
CREATE TABLE [FoodFruit](
PK, FK [FoodId] [int] NOT NULL,
PK, FK [FruitId] [int] NOT NULL)
The Model will only generate Food, Fruit entities.
But if I add a new column [Notes] to FoodFruit table, such as Notes:
CREATE TABLE [FoodFruit](
PK, FK [FoodId] [int] NOT NULL,
PK, FK [FruitId] [int] NOT NULL,
[Notes] [varchar](50) NULL)
The Model will generate Food, Fruit and FoodFruit entities.
So, I'm confused it, why the first one doesn't generate the FoodFruit entity.
That is correct behavior. In the first case your FoodFruit table is just database helper to model many-to-many relationship. EF doesn't need such helper in conceptual model so it hides this table behind directly modeled many-to-many relation. In the second case the table has additional data - it becomes full entity, not just junction table for relationship. EF detects it and map it as a new class.

How do I map Entity Framework many To many table with extra key part?

Is there a way to map this so that the parent tables Airport and Flight map to only the relevant part of the foreign composite key?
Using EF4.3 with Code First and Fluid API.
Each flight lands at one or more airports in a specific order. Without the additonal key property of FlightOrder, this mapping works.
Airport
- string Code
- List<AirportFlight> AirportFlights
Flight
- string Number
- List<AirportFlight> AirportFlights
AirportFlight
- string AirportCode
- string FlightNumber
- int FlightOrder
public AirportConfiguration() {
HasKey(x => x.Code);
HasMany(x => x.AirportFlights).WithRequired().HasForeignKey(x => x.AirportCode);
}
public AirportFlightConfiguration() {
HasKey(x => new { x.AirportCode, x.FlightNumber, x.FlightOrder });
}
public FlightConfiguration()
{
HasKey(x => x.Number);
HasMany(x => x.AirportFlights).WithRequired().HasForeignKey(x => x.FlightNumber);
}
This is Entity Framework generated schema:
CREATE TABLE Airports(
Code nvarchar(128) NOT NULL,
AirportFlight_AirportCode nvarchar(128) NULL, -- *** DO NOT WANT THIS ***
AirportFlight_FlightNumber nvarchar(128) NULL, -- *** DO NOT WANT THIS ***
AirportFlight_FlightOrder int NULL, -- *** DO NOT WANT THIS ***
CREATE TABLE Flights(
Number nvarchar(128) NOT NULL,
AirportFlight_AirportCode nvarchar(128) NULL, -- *** DO NOT WANT THIS ***
AirportFlight_FlightNumber nvarchar(128) NULL, -- *** DO NOT WANT THIS ***
AirportFlight_FlightOrder int NULL, -- *** DO NOT WANT THIS ***
CREATE TABLE AirportFlights(
AirportCode nvarchar(128) NOT NULL,
FlightNumber nvarchar(128) NOT NULL,
FlightOrder int NOT NULL,
CreatedDate datetime NOT NULL,
RowVersion varbinary(max) NULL,
CONSTRAINT PK_AirportFlights PRIMARY KEY CLUSTERED
(
AirportCode ASC,
FlightNumber ASC,
FlightOrder ASC
)
ALTER TABLE AirportFlights WITH CHECK ADD CONSTRAINT FK_AirportFlights_Airports_AirportCode FOREIGN KEY(AirportCode)
REFERENCES Airports (Code)
ALTER TABLE AirportFlights WITH CHECK ADD CONSTRAINT FK_AirportFlights_Flights_FlightNumber FOREIGN KEY(FlightNumber)
REFERENCES Flights (Number)
-- *** DO NOT WANT THIS ***
ALTER TABLE Airports WITH CHECK ADD CONSTRAINT FK_Airports_AirportFlights_AirportFlight_AirportCode_AirportFlight_FlightNumber_AirportFlight_FlightOrder FOREIGN KEY(AirportFlight_AirportCode, AirportFlight_FlightNumber, AirportFlight_FlightOrder)
REFERENCES AirportFlights (AirportCode, FlightNumber, FlightOrder)
-- *** DO NOT WANT THIS ***
ALTER TABLE Flights WITH CHECK ADD CONSTRAINT FK_Flights_AirportFlights_AirportFlight_AirportCode_AirportFlight_FlightNumber_AirportFlight_FlightOrder FOREIGN KEY(AirportFlight_AirportCode, AirportFlight_FlightNumber, AirportFlight_FlightOrder)
REFERENCES AirportFlights (AirportCode, FlightNumber, FlightOrder)
Thanks.
Fixed:
These properties were in the AirportFlights entity
- List<Airport> Airports
- List<Flight> Flights
Since you have mapped the join table as an entity, it does not have collection navigational properties to Airport and Flight. You have to model this as two one-to-many relationships. Remove List<Airport> Airports and List<Flight> Flights.
AirportFlight
- string AirportCode
- string FlightNumber
- int FlightOrder
However you can place navigationa proprties Airport and Flight on AirportFlight entity if you want.

Entity FrameWork - Exception on SaveChanges

I have this code saving a simple Entity:
ExecutionEngineEntities db = new ExecutionEngineEntities();
Task task = new Task();
task.Message = "Test";
task.Result = "Test";
task.Name = "Test";
db.Tasks.AddObject(task);
db.SaveChanges();
This is the exception:
A first chance exception of type 'System.Data.UpdateException' occurred in System.Data.Entity.dll
Unable to update the EntitySet 'Tasks' because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element to support the current operation.
The program '[6092] WebDev.WebServer40.EXE: Managed (v4.0.30319)' has exited with code 0 (0x0).
This is the create table code:
CREATE TABLE [dbo].[Tasks](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](50) NULL,
[Message] [nchar](1000) NULL,
[Result] [nchar](1000) NULL
) ON [PRIMARY]
After searching in google I found that mode people who got this error has a relation problems, this is not my case
Thanks
Maybe the answer here can help you: It has a DefiningQuery but no InsertFunction element... err
It could be that in the EF model it is configured that this entity is a view and not a table. Views don't support create, update or delete operations, so you can't insert.

Entity Framework This property descriptor does not support the SetValue

below are my entities which i have created using entity frame work.
retailer
id
name
childs(navigation)
generated database schema
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] nvarchar NOT NULL
childern
id
name
RETAILER(navigation)
generated database schema
[Id] [int] IDENTITY(1,1) NOT NULL,
[name] nvarchar NOT NULL
[Retailer_Id] [int] NOT NULL,
As you can see in the above model the relationship is 1 retailer can have 0 or 1 child. my problem is when i create a new child and set the retailer navigation property of it to a retailer entity it throws the following exception.how do i solve it
Error while setting property
'retailer': 'This property descriptor
does not support the SetValue
method.'.
Does the Retailer navigation property have its Setter property set to Public?