I have two LINQ to SQL classes, CandyBar and DeliciousCandyBar that map to tables of the same name in SQL Server.
There is a 0..1 relationship between CandyBar and DeliciousCandyBar. i.e, A CandyBar can have 0 or 1 DeliciousCandyBars. Conversely a DeliciousCandyBar has exactly one CandyBar.
In LINQ to SQL class, they look (basically) like
class CandyBar {
public int Id { get;set;} // this is primary key w/ autoincrement identity
public string Name {get;set;}
public EntityRef<DeliciousCandyBar> DeliciousCandyBar {get;set;}
}
class DeliciousCandyBar {
public int DeliciousnessFactor {get;set;}
public int CandyBarId {get;set;} // FK to candyBar Id
public EntityRef<CandyBar> CandyBar {get;set;} // the association property of the FK
}
To feed the database (via l2sql), my crawler goes out and finds candy bars and delicious candy bar.
But, with the first delicious candy bar my crawler inserts into the CandyStoreDataContext, the DataContext throws an exception when SubmitChanges is called.
The crawler runs the following code for one delicious candy bar. Please note this is an example. The exact process is more complex and I use a custom DSL crawler that spits out this object structure. Essentially, the following is performed.
var dc = CandyStoreDataContext();
var bar = new CandyBar() {
Name = "Flake",
DeliciousCandyBar = new DeliciousCandyBar() {
DeliciousnessFactory = 12
}
};
dc.CandyBars.InsertOnSubmit(bar);
dc.SubmitChanges();
On SubmitChanges(), a SqlException is thrown with the message "The INSERT statement conflicted with the FOREIGN KEY constraint FK_CandyBar_DeliciousCandyBar. The conflict occured in database CandyStoreData, table 'dbo.DeliciousCandyBar', column 'CandyBarId'".
The problem became clear when I dumped the CandyStoreDataContext.Log to Console.Out, the generated insert statements were round the wrong way. LINQ to SQL was trying to insert the DeliciousCandyBar first (which tried to set an invalid value in CandyBarId column), rather than inserting CandyBar first.
My question is, how do I get Linq to SQL to swap with the order of the insert statements?
I had assumed (incorrectly) that LINQ to SQL would know the direction of relationship dependency and do it the other way around.
UPDATE:
This post suggests I have the Association the wrong way around. But that doesn't make sense to me. It makes sense when modelled in the database. How could this be done the other way around.
On CandyBar, the association attribute on DelciousCandyBar property is
[Association(Name="DeliciousCandyBar_CandyBar", Storage="_DeliciousCandyBar", ThisKey="Id", OtherKey="CandyBarId", IsForeignKey=true)]
On DeliciousCandyBar, the association attribute on CandyBar property is
[Association(Name="DeliciousCandyBar_CandyBar", Storage="_CandyBar", ThisKey="CandyBarId", OtherKey="Id", IsUnique=true, IsForeignKey=false)]
Okay, now I'm confused, why is the second attribute marked as the foreign key.
I'm going to try recreating that relationship between CandyBar and DeliciousCandyBar in SQL Management studio
UPDATE 2
Okay, I tried creating the relationship both ways. And SSMS makes it really clear where the primary key is located (CandyBar.Id). I had it right the first time. Otherwise, the cascading would go backwards.
I would consider the possibility of it being a linq2sql bug with self referencing tables. Its a wild guess, but I recall linq2sql documentation saying somewhere it didn't support it that well. Perhaps there its the linq2sql designer that gets confused.
From the generated properties you posted, you can tell it has it backwards i.e. CandyBar has is pointing to delicious, instead of the other way around. Look at the generated code for other relations that work correctly.
Once you confirm it isn't working, and that by re-adding them in the designer doesn't sets them correctly, open the properties of a working association in the designer and make sure to have the association between candybar and deliciouscandy configured in the same way.
Please try this alternative:
Insert the instance of CandyBar without any child DeliciousCandyBar objects, then call the SubmitChanges() method.
Assuming you have an ID or GUID linking the two objects - lets say, CandyBarID. Then set the value of CandyBarID on the DeliciousCandyBar instance to that of the instance of CandyBar.
You could then insert the DeliciousCandyBar object, and because CandyBarID has been set, the relationship should be correct on selecting CandyBar objects.
Related
For school I'm working on a project in C# WPF and SQL Server. I made the database and use Linq to SQL. Now I got the following tables:
Patients
-------
ID int PK
name varchar
insurancecompany int FK
Insurancecompanies
-------
ID int PK
name varchar
insurancecompany in patients is a FK to id in insurancecompanies
I left out a lot of unnecessary columns for my question since it would take too long. So I added the database tables to my Linq to SQL database model. I created an instance to the patient class. Looking at it, I see 2 properties. One is insurancecompany, which is an int. The other is insurancecompany1, which is an insurancecompany type.
Is it safe to make the int private, or remove it? Or is there a way to make it so there's only one property?
What is happening is that database model sees that you have a foreign key relationship to Insurancecompanies, it looks at the value you've assigned it and then finds that insurancecompany and adds it as an additional property which it calls "insurancecompany1" (it would have called it "insurancecompany" but couldn't because you already have a property with that name).
This is a nice feature because it makes it easy to look at the insurance company for a given patient without needing to use joins;
var dave = patient();
//assign a patient from your database to "dave" here..
var nameOfDavesInsuranceCompany = dave.insurancecompany1.name;
If you remove the int insurancecompany you will loose this feature because the model would no longer be able to work out which insurance company to look at. You could make it private but you would loose the ability to assign an insurance company to patient by simply giving an int value (you would always have to set an insurancecompany object to insurancecompany1).
If you don't like the names, you could rename insurancecompany to something like insurancCompanyId and then call insurancecompany1 insuranceCompany.
We have a synchronization framework that uses a global SyncEntity table to keep track of which entities have been updated at what time, meaning we have a global table with a structure something like this:
<dbo.SyncEntity>
ID int
EntityType int
EntityGuid uniqueidentifier
The EntityType is an enum that corresponds to the specific entity so that we know in which table to look for this entity.
All our tables have an ID (PK) and a GUID.
I have created a Foreign Key constraint from the different Entity tables and to the EntityGuid in the SyncEntity table.
This works perfect for existing data however when we use EntityFramework to insert new data it doesnt insert the data in the "correct" order resulting in an error because the SyncEntity with the required EntityGuid is not yet inserted.
I guess we could add a property SyncEntity on all of our entities however i really dont want to pollute our domain model with that property.
So my question, is there anyway to ensure that specific Entity types are inserted as the first entities?
Or is there anyway to map the relation from Guid (on the specific Entity) to EntityGuid (on SyncEntity) without a navigation property.
I see two ways you could potentially alleviate this issue.
First, you could use domain events to recognize that a new entity has been created and raise an event, passing in the entity itself as a parameter and then allow that event to create a new SyncEntity insert it and then save it. This will populate your ID and then you can assign it to the new entity creating the relationship.
Second, you could override the SaveChanges method of the DbContext to look at added entities and then create a new record for each of them, then assign your new SyncEntity Ids to the entity.
WHy would you bother EF with something like that?
Have the SyncEntity entry created by a trigger on the tables. Finished. EF does not have to bother with it.
And it is save for direct SQL usage, too.
EF is a good tool - though only a very very mediocre ORM. But it is not a solution for everything. DB internal logic, like a logging table, should be handled in the database.
I was reading this article http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx and was trying to figure out how to create private setters (the section in the article DbContext with read-only set properties is right before the summary). How would you create private setters? I was playing around with different methods but nothing seemed to work. I am doing this because I need to group the original table based on a query I have because the original table is a heap and I need a primary key for the entity. So anytime a client asks for this table it is already grouped. Not even sure if this is the correct way to do that. Thanks.
EDIT: sorry for being vague. I am doing code first. For example there exists a SQL Table with JobNbr, Qty and Date and I need to group by JobNumber, sum on Qty and take the oldest expiration date, and that will be my entity since this table has no primary key. The way I am doing it now gives me the error below from a method I created in the DbContext class. I do have a EntityTypeConfiguration class. Do I do this in that class?
EDIT: : you might be wondering why I am doing this. Basically I need to get data from the heap and save it in another database. My original approach was database.SqlQuery() to get grouped rows from the heap, but sometimes I have too many parameters for execute_sql. So I decided to create an entity for the grouped query without tracking changes (since all I am doing is reading from the table and saving to another DB). See my post here with the issue I am having https://stackoverflow.com/questions/22106030/entity-framework-6-this-database-sqlquery-character-limitation-with-sp-executes. The only way I know to get around it is to create an entity (even though in this case the entity is a query and not a table).
The entity or complex type
' cannot be
constructed in a LINQ to Entities query.
Update
Added mappings below
Question summary
I have a database with many required foreign key fields and a code base with many unidirectional associations. I want to use NHibernate, but as far as I can tell, I either have to make the foreign key fields in the database NULLable (not a realistic option) or change the associations to bidirectional (not ideal either). Any other options that I've missed?
Backgrounds
I've joined a project that uses NHibernate to map tables 1:1 to so-called "technical" objects. After data retrieval, the objects are mapped to the actual domain model (AutoMapper style,implemented differently). I know that this is an unnecessary step and I want to propose removing it to the team. However, I'm running into an issue.
The domain model contains many unidirectional associations: the Case object has a list of Persons associated with the case, but the Persons do not hold a reference to the Case object. In the underlying database scheme, the Person table has a required foreign key field that references the case Id. The data model:
[ERD]
PERSON
CASE Id* Ids are generated by the DB
Id* <--FK-- CaseId* * denotes required fields
(other) (other)
The domain model looks like this:
public class Person : DomainEntity
{ // DomainEntity implements Id. Non-essential members left out }
public class Case : DomainEntity
{
public virtual IList<Person> Persons { get; set; }
}
Calling session.Save() on a Case leads to a database error (CaseId required when inserting into Person), because NHibernate starts with inserting the Person entries, followed by the Case entry and finishes by updating the CaseId column in the Person entries. If the CaseId column in the database is altered to non-required (allow NULLs), everything works as it should... however, that change is not an option at the moment (the database model is shared by several apps for at least another year).
The only way I have found to get NHibernate to execute the database actions correctly is by changing the association to bidirectional, i.e., by changing Person to
public class Person : DomainEntity
{
public virtual Case Case { get; set; }
}
This would involve significant changes to the existing codebase however, so I would prefer alternatives, if they exist. I've played around with component mappings, but that is a bad fit since most associations in our model are not actual (UML) compositions. Are there any other options that I've missed? TIA!
EDIT
The (Fluent) mapping for Case looks like this:
public class CaseMapping : ClassMap<Case>
{
public CaseMapping()
{
Not.LazyLoad();
Id(c => c.Id).GeneratedBy.Identity();
Map(x => x.Code).Not.Nullable().Length(20);
Map(x => x.Name).Not.Nullable().Length(100);
HasMany<Person>(x => x.Persons)
.AsBag()
.KeyColumn("CaseId")
.ForeignKeyConstraintName("FK_Person_Case")
.Cascade.AllDeleteOrphan();
}
}
If I use SessionSource.BuildSchema for a test database, this generates a Person table with a nullable CaseId column. I have not found a way for this to work with a non-nullable CaseId field without bidirectional associations. The executed (pseudo) SQL statements:
INSERT INTO Case...
select ##identity
INSERT INTO Person /* (all columns except CaseId) */
select ##identity
UPDATE Person SET CaseId = ? WHERE Id = ?;#p0 = 2, #p1 = 1
I think you may be out of luck here. The docs at http://nhibernate.info/doc/nh/en/index.html#collections-onetomany state:
If the column of a association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true"
Short Question:
Basically I am trying to add a scalar property to my entity which holds the ID of a FK entity.
What I have tried to do thus far:
What I have tried so far is adding the scalar property (called ChildId) and mapped it to the matching column in the database. Now as you can imagine I get some exceptions when I try and do this because entity framework complains that the FK id is being managed in two places, once through x.ChildId and the other through x.Child.ChildId.
Now I get why it is doing this but I need some why to be able to have a scalar property which is automatically populated with the ChildId.
What I know I could do but really don't want to:
I realize that I could write a linq query that does something like the following (where I have implemented the other half of the partial class and added a property there called ChildId):
from x in db.Parent
select new Parent { ParentName = x.ParentName, ..., ChildId = x.Child.ChildId }
But this is extremely messy, particular when I have 30 odd queries that return a parent object, this mapping would need to be repeated for each query...
Also I realize that after I have executed the query I could go something like:
var childId = parent.Child.Id;
But this would cause either an extra query to be triggered, or if I was proactively loading child, and in either case I would be pulling out a lot more data than I need when I only want the ID...
The required end result:
So how do I get around some of these limitations so that I can write my queries like so (or something very similar):
from x in db.Parent
select x
And have it so that I can either go:
var childId = parent.Child.Id; //Where in this case the only property retrieved would be the Id
//Or
var childId = parent.ChildId;
Cheers
Anthony
EDIT:
Hey thanks for the reply...
I just figured this out for myself as well. Basically I was thinking that if EF supports lazy loading it must be storing the ID somewhere. Then it clicked that it must be in the reference... Hence for me it worked out being something like:
destination.PlanTypeId = (int)source.PlanTypeReference.EntityKey.EntityKeyValues[0].Value;
Also thanks for the idea of creating the extension property... will be very useful.
Did you try using parent.ChildReference.EntityKey? It doesn't need to be additionaly loaded and is holding FK. You can write extension method to get key easier.