I have an entity that maps to a table called Rule. The table for this entity has an FK to another Table called Category. I'm trying to figure out how to pull in a property from Category in my Rule entity. I'm pretty sure I want to use a join in my entity mapping, but I can't figure out how to configure it so that it works. Here is my mapping:
Join("Category", x =>
{
x.Map(i => i.CategoryName, "Name");
x.KeyColumn("CategoryId");
x.Inverse();
});
Here is the SQL that it's generating...
SELECT ...
FROM Rule rules0_ left outer join Category rules0_1_ on rules0_.Id=rules0_1_.CategoryId
WHERE ...
Here is the SQL that I want.
SELECT ...
FROM Rule rules0_ left outer join Category rules0_1_ on rules0_.CategoryId=rules0_1_.Id
WHERE ...
I can't seem to find anything on the JoinPart that will let me do this. Subselect looks promising from the little bit of documentation I've found, but I can't find any examples of how to use it. Any advice on this problem would be much appreciated. Thanks!
"Join" is poorly named. a "join" in an NHibernate mapping implies a zero-to-one relationship based on a relation of the primary keys of the two tables. You would use a join if, for instance, you had a User table and a UserAdditionalInfo table, with zero or one record per User. The UserAdditionalInfo table would likely reference the PK from User as both a foreign key and its own primary key. This type of thing is common when a DBA has to religiously maintain a schema for a legacy app, but a newer app needs new fields for the same conceptual record.
What you actually need in your situation is a References relationship, where a record has a foreign key relationship to zero or one other records. You'd set it up fluently like so:
References(x=>Category)
.Column("CategoryId")
.Inverse()
.Cascade.None();
The problem with this is that Category must now be mapped; it is a separate entity which is now related to yours. Your options are to live with this model, to "flatten" it by making the entity reference private, changing the mapping to access the entity as such, and coding "pass-throughs" to the properties you want public, or by using a code tool like AutoMapper to project this deep domain model into a flat DTO at runtime for general use. They all have pros and cons.
Related
I have created a view "Supplier" that shows columns from a table "T_ADDRESS". The view is declared as (I know, the '*' is a no-go in views)
create View Supplier as
select * from T_ADRESSEN where IsSupplier = 1
In EF, I want to use the view as it is more readable than the ugly "T_ADRESSEN". So far so easy.
Now comes the tricky part (for me). The table T_ADDRESS has a self referencing foreign key "MainAddressId" which points to T_ADDRESS.
Creating a DB-first (or CodeFirst from DB) will create the FK relationship for the table T_ADDRESS (and the navigational properties), but not for the view 'Supplier'. Of course not: EF does not know anything about the FK relationship (although the view exposes the same columns).
Now I tried to use the 'ForeignKey' and 'InverseProperty' attributes in my code first model on the Supplier-class but this gives me an ModelValidationException. Also clear: There is no such FK-relationship.
How can I tell EF to treat a field just like a foreign key although the constraint does not exist?
What I am trying to do is to have 'Suppliers' in my EF model (as a subset of T_ADDRESS). If there is another way to do it, I would be happy to receive a hint.
You can't define ForeignKey and InverseProperty on a view. In your case, you need to use that ugly T_ADRESSEN table and use [AutoMapper][1] to map it the to the DTO class. In your case, T_ADRESSEN is the context table and Supplier is your DTO class.
with AutoMapper you can do something like this:
var ugly = context.T_ADRESSEN.Where(e=>e.IsSupplier ==1);
var suppliers = mapper.Map<IEnumerable<Supplier>>(ugly);
where mapper is IMapper interface defined in AutoMapper.
Sometime one should figure out that the DTO mapping technique as a replacement to the traditional database view.
I use code first of Entity framework. There are two classes "Question" and "User". I defined a relationship as below:
this.HasRequired(v => v.Creator).WithMany(v => v.Questiones)
.HasForeignKey(v => v.CreatorId).WillCascadeOnDelete(false);
After gernerating the database I found that it always create foreign key between Id of User and CreatorId of Question. Because of lower performance of FK(and other reason),I want to define navigation property relationship without setting foreign key in database? Delete FK after EF created it?
If cannot do this using fluent api, could you tell me why EF designed in this way please?
About the lower performance of FK. I have a User table with 5 Million records in it. when I insert a Question into db, since the db check the question.CreatorId validation from User table, it always slower than without FK.
And there are many other reasons that I need to remove FK.
I think I am somewhat obsession because I think that deleting FK after created it is strangely and ugly. What i want is implementing this by using something like WithoutForeignKey in fluent api:
this.HasRequired(v => v.Creator).WithMany(v => v.Questiones)
.WithoutForeignKey(v => v.CreatorId).WillCascadeOnDelete(false);
Without questioning why are you trying to do this strange thing and going just to the answer: you could delete fk constraint after generated, or you could use migrations and remove FK generation from the migration code.
SQL code generated when traversing nav properties will work even if fk constraint doesn't exist, except for cascade deleting
If you want a relationship between two tables, you need to define a foreign key. No way around it. Even if you use Map() in fluent api, you can only hide the foreign key in your model, in the background EF will still use it and it will exist in the database.
Also I don't get what you mean by "performance" of foreign key? One extra (likely small) column won't make a difference. If you mean the navigation properties for the performance part, you can do 3 things:
Don't include them in your model
Make them non-virtual to disable lazy loading
Disable lazy loading all together with ctx.Configuration.LazyLoadingEnabled = false;
If you don't want to tell db about relation and treat both entities as not related (I wonder why), then just ignore these navigation properties and FK field. Note that you will be responsible for managing related entities: saving and loading them from db, updating ids etc
this.Ignore(q => q.Creator);
this.Ignore(q => q.CreatorId);
And you also need to ignore other side of relation, otherwise EF will generate FK column with default name Creator_CreatorId. So in Creator entity configuration:
this.Ignore(c => c.Questiones);
I'm following this tutorial in order to implement a local database (using SQLite) for my WPF application.
Everything works as it should, although I have a logical problem I don't know how to solve using this approach. I'll simplify it below.
Database-wise, I have 2 tables (A,B) which share a many-to-many relationship, and thus require a JOIN table as well (ABJoin).
In my actual code however, I'd like to use only 2 models: A and B, which each having a list of the other type. Like this:
public class A {
// ...fields
List<B> bList;
}
public class B {
// ...fields
List<A> aList;
}
How can it be implemented in EF+SQLite?
Searching online, I have found some solutions, but nothing that applies to SQLite, so I was not sure how they'd work.
Configure Many-to-Many Relationships in Code-First
If you are using many to many join table then your each class should have a list of the join table.
It cannot work the way you are thinking.
Are you sure that it is a good idea not to have a third entity?
Lets say your two entities were DepartmentStore and Product, a typical example for an n:n relationship. A department store can sell many products and a product may be available in many departments stores. This results in a third entity which connects the two above, in the example above this would something like ProductAvailability.
If you think about it more careful, then you might realize that the new connecting entity might have properties of its own. In my example this might be NumberOfProducts, will states the available quantity of a product in a certain department store.
In my experience, it is quite common for the connecting entity to have a real value that goes beyond just connecting two other entities.
I also took a look at you example which it about Album and Artist entities.
Do you want to make a data model where an Album can be created by more than one Artist?
Entity Framework doesn't have automatic many-to-many mapping.
Instead of this, you can map A and B to intermediate table as one-to-many.
If you are not obliged to use only EF, I suggest to try NHibernate ORM instead.
It has convenient many-to-many mapping and generally more powerful.
In EF cross reference tables are abstracted away by creating many-to-many relationships. E.G.
There's a SQL table dbo.TrialContactCrossReference that relates TrialContactId to TrialID. Now, EF did not generate an Entity TrialContactCrossReference because it went with this MANY-MANY relationship thing. How do I add a new row to said table?
I tried
context.TrialContacts.??? and context.ClinicalTrials.??? and just don't know what to do with this. If I have a new Contact that I want to relate to a trial how am I supposed to go about it?
trial.Contacts.Add(contact);
OR
contact.Trials.Add(trial);
OR (and my advise)
you could create an additional entity for cross reference table. this will convert many-many to 2 one-many relationships. more then %90 cases crosstables has additional columns (at least IsActive, RecordDate etc.) even it doesnt, it may be so in future and it requires you make lots of changes in code.
If I have a new Contact that I want to relate to a trial how am I supposed to go about it?
Assuming you have an existing Contact instance just do:
trial.TrialContacts.Add(contact);
context.SaveChanges();
EF will take care of the intermediate table insert for you. Note that adding Contacts and Trials works the same as if they weren't related.
There's a trick that was not obvious to me when setting this up. TableA must be added to TableB, not just to itself. In fact, looking at the generated entities each entity has a List<> of the other entity.
class TableA
{
List<TableB> TableB;
}
class TableB
{
List<TableA> TableA;
}
For example, if I want to add a TrialContact to a ClinicalTrial then I write:
context.ClinicalTrials.TrialContacts.Add(trialContact);
context.SaveChanges()
Then the xRef table be updated to reflect the relationship.
I am writing some very generic database code, and I would like to find a way to query a set of types in my entity set (using LINQ to SQL EntityFramework, database-first) which are related to another entity.
So, for example I might have a Product belong to a Category;
SELECT * FROM Products p INNER JOIN Categories c ON p.CategoryId = c.Id
In my database, p.CategoryId is a Foreign Key constrain to be NON-NULL. (i.e; a Product MUST belong to a Category).
Now, if I try to DELETE FROM Categories, I get errors, as there are Products still related to Categories, and I do not have (or want) a CASCADE DELETE applied to the relationship.
What I want to do is examine my DataContext library, and determine dynamically that Categories are key'd by Products, and so if I want to DELETE from Categories, I will first need to DELETE from Products.
By 'dynamically', I mean that my code will not have fore-knowledge of the types or relationships (it does not know about Product or Category entities specifically) but I am willing to use Reflection to assess the DLL to work out these relationships.
I have looked at the DataContext-related code, and can see EntityRef properties on certain Entities (which is half the problem solved), but I can't seem to find any way to tell if these relationships are mandatory or optional (i.e; NON-NULL or NULLABLE) in the underlying database.
?
You know you can automatically cascade deletes in Entity Framework by setting the Delete Rule to "Cascade"? That may make things easier (while not necessarily providing a generic solution for LINQ to SQL).
Take a look here for more info:
http://msdn.microsoft.com/en-us/library/bb738695.aspx