Create an Entity Type and an Association from the same table - entity-framework

Is it possible to have both an entity type and a many-many association backed by the same table? I’ve tried a couple different approaches and they all fail with different errors.
First I tried creating the model from the database then creating an association in the designer.
It gives me the proper Foos and Bars navigation properties, but it's not backed by any table and fails when I try to execute a query.
Model1.msl(3,4) : error 3027: No mapping specified for the following EntitySet/AssociationSet - BarFoo.
So I tried mapping the association to the FooBar table in the designer. Only FooREF and BarREF are part of the association, but EF expects the primary key to be mapped as well.
ERROR (3025): Problem in Mapping Fragment starting at line 32: Must specify mapping for all key properties (FooBar.ObjectID) of table FooBar.
Since I’m not able to map the ObjectID and RowVersion, I tried to exclude them by using a QueryView in the edmx.
<edmx:Mappings>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
<EntityContainerMapping StorageEntityContainer="TestModelStoreContainer" CdmEntityContainer="TestEntities">
<EntitySetMapping Name="Bars">
<EntityTypeMapping TypeName="TestModel.Bar">
<MappingFragment StoreEntitySet="Bar">
<ScalarProperty Name="ObjectID" ColumnName="ObjectID" />
<ScalarProperty Name="Count" ColumnName="Count" />
<ScalarProperty Name="RowVersion" ColumnName="RowVersion" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Foos">
<EntityTypeMapping TypeName="TestModel.Foo">
<MappingFragment StoreEntitySet="Foo">
<ScalarProperty Name="ObjectID" ColumnName="ObjectID" />
<ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="RowVersion" ColumnName="RowVersion" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="FooBars">
<EntityTypeMapping TypeName="TestModel.FooBar">
<MappingFragment StoreEntitySet="FooBar">
<ScalarProperty Name="ObjectID" ColumnName="ObjectID" />
<ScalarProperty Name="RowVersion" ColumnName="RowVersion" />
<ScalarProperty Name="BarREF" ColumnName="BarREF" />
<ScalarProperty Name="FooREF" ColumnName="FooREF" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<AssociationSetMapping Name="BarFoo" TypeName="TestModel.BarFoo" >
<EndProperty Name="Foo">
<ScalarProperty Name="ObjectID" ColumnName="FooREF" />
</EndProperty>
<EndProperty Name="Bar">
<ScalarProperty Name="ObjectID" ColumnName="BarREF" />
</EndProperty>
<QueryView>
SELECT VALUE TestModel.BarFoo(CREATEREF(TestEntities.Foos, row(f.FooREF), TestModel.Foo), CREATEREF(TestEntities.Bars, row(f.BarREF), TestModel.Bar))
FROM TestModelStoreContainer.FooBar AS f
</QueryView>
</AssociationSetMapping>
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
But despite the QueryView element being documented, its addition causes the schema validation to fail.
MappingException: Schema specified is not valid. Errors:
<File Unknown>(39,8) : error 2025: XML Schema validation failed for mapping schema. Schema Error Information : The element 'AssociationSetMapping' in namespace 'http://schemas.microsoft.com/ado/2009/11/mapping/cs' has invalid child element 'QueryView' in namespace 'http://schemas.microsoft.com/ado/2009/11/mapping/cs'. List of possible elements expected: 'Condition, ModificationFunctionMapping' in namespace 'http://schemas.microsoft.com/ado/2009/11/mapping/cs'..
Is there a strategy I'm missing here? In the end I'd like to be able to treat FooBar as an entity while also keeping the Foos and Bars navigation properties. Is this possible?

Related

Two entities mapped to the same rows

I'm getting the following error on my database first model in Entity Framework:
Error 3032: Problem in mapping fragments starting at lines 3434,
4312:EntityTypes Model.Docent, Model.Student are being mapped to the
same rows in table Attendee. Mapping conditions can be used to
distinguish the rows that these types are mapped to.
While I already added conditions to these models:
<EntityTypeMapping TypeName="IsTypeOf(Model.Student)">
<MappingFragment StoreEntitySet="Attendee">
<ScalarProperty Name="Id" ColumnName="atnId" />
<Condition ColumnName="atnTypeId" Value="1" />
</MappingFragment>
</EntityTypeMapping>
And
<EntityTypeMapping TypeName="IsTypeOf(Model.Docent)">
<MappingFragment StoreEntitySet="Attendee">
<ScalarProperty Name="AvailabilityApprovedByType" ColumnName="atnAvailabilityApprovedByAttId" />
<ScalarProperty Name="Id" ColumnName="atnId" />
<Condition ColumnName="atnTypeId" Value="2" />
</MappingFragment>
</EntityTypeMapping>
Their is a more complex hierarchy, possibly that's the problem. But I'm unsure how to proceed. This a the hierarchy:
Attendee (Abstract)
-> Facility (Type = 3)
-> AttendeeCollection (Abstract)
-> Team (Type = 4)
-> Group (Type = 5)
-> Person (Abstract)
-> Student (Type = 1)
-> Docent (Type = 2)
Well I figured out the problem. The Person entity had mapped scalar properties and associations. The associations where the problem. Because they could be of two types. I could not write in a condition for them because they could map to two properties. So I removed the scalar properties and the table mapping for the Person class altogether.
After that I implemented private versions of these scalar properties on the Docent en Student class. And exposed them via a partial implementation. Where I added them as abstract to the Person class.
I hope this is clear and helps somebody else. Possibly somebody else can write it down more legible.

Entity framework 4 - Adding a object without Identity column throws OptimisticConcurrencyException

I have a database first approach, using EF4 on Sybase.
SSDL
<EntityType Name="tq_qmt_logger">
<Key>
<PropertyRef Name="qmt_id" />
</Key>
<Property Name="qmt_id" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="client_id" Type="varchar" Nullable="false" MaxLength="100" />
<Property Name="logged_date" Type="datetime" Nullable="false" />
CSDL
I have corresponding CSDL with annotation:StoreGeneratedPattern="Identity"
Now my source code is,
tq_qmt_logger qmtLogger = new tq_qmt_logger();
qmtLogger.client_id = machineID;
qmtLogger.logged_date = DateTime.Now;
// qmtlogger.qmt id is omitted because it is
// generated by a sequence in the DB.
context.tq_qmt_logger.AddObject(qmtLogger);
context.savechanges()
SaveChanges throws OptimisticConcurrencyException with error Store update, insert, or delete statement affected an unexpected number of rows (0). My guess is, EF passes 0 to my qmt_id (identity) column, which is getting rejected. Can someone guide how to fix this?

In Entity Framework, getting the value of an identity column after inserting

I'm using EF4. I want to insert a new MyObject into the database. MyObject has two fields:
Id: int (Identity) and
Name: string
As I've seen in documentation Entity Framework is supposed to set MyObject.Id to the value generated by database after the call to SaveChanges() but in my case that doesn't happen.
using (var context = new MyEntities())
{
var myObject = MyObjects.CreateMyObject(0, "something"); // The first parameter is identity "Id"
context.MyObjects.AddObject(myObject);
context.SaveChanges();
return myObject.Id; // The returned value is 0
}
UPDATE:
This happens in one of my entities and others work fine. By the way, I checked and the DB column is identity and StoreGeneratedPattern is set to Identity.
Here is the SSDL. I don't see any difference. The first one isn't working right:
<EntityType Name="OrgUnit">
<Key>
<PropertyRef Name="Srl" />
</Key>
<Property Name="Srl" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="TypeId" Type="smallint" Nullable="false" />
<Property Name="Name" Type="varchar" Nullable="false" MaxLength="80" />
</EntityType>
<EntityType Name="OrgType">
<Key>
<PropertyRef Name="Srl" />
</Key>
<Property Name="Srl" Type="smallint" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="Title" Type="varchar" Nullable="false" MaxLength="120" />
<Property Name="Options" Type="int" Nullable="false" />
</EntityType>
The update is done successfully in the database and the identity is generated but the entity object is not updated with the new identity.
In that case, you EF model is probably not up to date - EF should automagically get your new ID from the database. Try refreshing your EF model.
Your identity column's properties should look like this in your EDMX model:
If you're using Oracle Entity Framework 4 Provider, like I do, from ODP.NET, there is a bug in Designer. Just selecting the Identity value in drop down box will not do. It will annotate the conceptual property in conceptual model with
annotation:StoreGeneratedPattern="Identity"
like in
<Property Type="Int32" Name="Id" Nullable="false" cg:SetterAccess="Private" annotation:StoreGeneratedPattern="Identity" />
But, it will fail to do the same for Storage Model, ie. you need to do it manually. Find the Property (in my case ID) in EntityType of interest and add StoreGeneratedPattern="Identity".
<EntityType Name="PROBLEMI">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="number" Nullable="false" Precision="10" StoreGeneratedPattern="Identity" />
I'm not aware of the same bug in SQL EF provider 'cos I didn't use it.
This should "just work." Make sure the DB column actually is IDENTITY, and that StoreGeneratedPattern is set to Identity in EDMX.
wow! that was a nightmare but at last I solved it, although I didn't understand what the problem was. Maybe this helps someone with the same problem.
Generate the script for creating the table and its data.
Drop the table.
Run the script.
If you are using Linq To Entities, and get this error even if you followed the advices of marc_s (that are really good), you should look at your entites directly in the edmx (xml view) and check if they have the following attribute :
<EntityType Name="MyEntity">
<Key>
<PropertyRef Name="pk" />
</Key>
<Property Name="pk" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="value" Type="float" Nullable="false" />
</EntityType>
The StoreGeneratedPattern="Identity" is also required.
Try using refresh method after Save Changes, it has been documented in MSDN
"To ensure that objects on the client have been updated by data source-side logic, you can call the Refresh method with the StoreWins value after you call SaveChanges."
http://msdn.microsoft.com/en-us/library/bb336792.aspx
Though i feel what #Craig has suggested might also work.
I ran into this today. The difference though was I was using an insert function, where the above person doesn't specify that. What I had to do was make my insert function stored procedure return SCOPE_IDENTITY() and use a result binding for the id returned.
Fixed my issue.

Table per hierarchy layout problems in EF 4.1 with multiple nullable discriminators

I have a table with an int PK, one NOT NULL field, and two NULL string fields.
When I go and set up a TPH-style design in EF, I set it up this way:
The top level type only has the PK and the NOT NULL field.
The first level checks the first nullable field as a discriminator. The not null resulting type is abstract. I map the field accordingly.
I do this again for the second field, again mapping where not null. I set nullable = false on the fields I map.
<EntitySetMapping Name="Items">
<EntityTypeMapping TypeName="IsTypeOf(Model1.Item)">
<MappingFragment StoreEntitySet="Items">
<ScalarProperty Name="ID" ColumnName="ID" />
<ScalarProperty Name="OtherID" ColumnName="OtherID" />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(Model1.BothNullItem)">
<MappingFragment StoreEntitySet="Items">
<ScalarProperty Name="ID" ColumnName="ID" />
<Condition ColumnName="FirstNullField" IsNull="true" />
<Condition ColumnName="NullField2" IsNull="true" />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(Model1.FirstFieldNull)">
<MappingFragment StoreEntitySet="Items">
<ScalarProperty Name="ID" ColumnName="ID" />
<ScalarProperty Name=FirstNullField" ColumnName="FirstNullField" />
<Condition ColumnName="FirstNullField" IsNull="false" />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(Model1.NotNullSubItem1)">
<MappingFragment StoreEntitySet="Items">
<ScalarProperty Name="ID" ColumnName="ID" />
<Condition ColumnName="NullField2" IsNull="true" />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(Model1.NotNullSubItem2)">
<MappingFragment StoreEntitySet="Items">
<ScalarProperty Name="ID" ColumnName="ID" />
<ScalarProperty Name="NullField2" ColumnName="NullField2" />
<Condition ColumnName="NullField2" IsNull="false" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
I'm getting "two entities with different keys are mapped to the same row."
I am thinking it's because maybe the first item's not null attribute is not getting inherited by the children.
I've created a third type to try to take care of the case of NullField1 being null and NullField2 not being null (which will not happen in my DB, I have a constraint), but even if I added it it doesn't work.
Explicitly adding the not null condition on either of the 2 sub children requires me to map the column, which still doesn't work even if I map it to some extraneous property.
None of the combinations of conditions for "BothNullItem" works either.
Any ideas?
Welp, I ended up giving up on trying to get discriminator columns to propagate through inheritance so I created 3 views, one top level, one for null field1 and not null field one, and then on not null field one, I make field2 the discriminator column in EF. This sounds like a crappy answer to my problem so I'd like to hear from someone in the know what the deal is. Buehler?
UPDATE: FIXED! Going off of the horizontal partitioning concept in one of the articles I found on msdn (http://msdn.microsoft.com/en-us/library/cc716779.aspx)I went in and manually added the conditions in the msl. It looks like you can't have this work automatically from the designer. For those of you wondering, open the edmx in the xml editer and go down and look at the conditions elements of your mappings. Add in extra conditions where needed (apparently conditions don't inherit from parent entities so you have to manually add them to the children) and compile!

function import in entity framework error

hi i have an error in the entity framework. i imported the sp get() into EF and return results as complex datatype 'GetResult'.In the edmx xml i have set the 'Amount' type to decimal.
<ComplexType Name="Get_Result">
<Property Type="String" Name="Description" Nullable="true" MaxLength="255" />
<Property Type="Decimal" Name="Amount" Nullable="false" />
<Property Type="Decimal" Name="Gst" Nullable="false" Precision="19" />
<Property Type="Decimal" Name="Total" Nullable="true" Precision="19" />
</ComplexType>
I try to bind the result with datagridview
gridview.DataSource = db.Get().ToList();
it kept giving me error message like this. and i couldn't find int32 anywhere in EF and have updated & built the EF multiple times.
The 'Amount' property on 'Get_Result' could not be set to a 'Int32' value. You must set this property to a non-null value of type 'Decimal'.
any help appreciated...
solved the issue by handling null exception