I looked at this SO question.
I want to do something similar in EF 5. I don't see the ForeignKey attribute but instead an Association attribute in EF5.
Also, can someone explain what this does/means :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Match>()
.HasRequired(m => m.HomeTeam)
.WithMany(t => t.HomeMatches)
.HasForeignKey(m => m.HomeTeamId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Match>()
.HasRequired(m => m.GuestTeam)
.WithMany(t => t.AwayMatches)
.HasForeignKey(m => m.GuestTeamId)
.WillCascadeOnDelete(false);
}
This is the explanation :
Primary keys are mapped by default convention. Team must have two
collection of matches. You can't have single collection referenced by
two FKs. Match is mapped without cascading delete because it doesn't
work in these self referencing many-to-many.
What I want to do is very similar to the example in the link but I don't know :
When I need to modify DbContext
When the primary keys will link to each other
When I need to explicitly use Association to create the relationship
Any explanation is appreciated.
Okay so... I can't answer the ForeignKey attribute question on EF beta for I haven't had the chance to check it out yet.
However...
modelBuilder.Entity<Match>() - Take the entity "Match" and perform following operations on it
.HasRequired(m => m.HomeTeam) - The entity needs to have a non-null navigation HomeTeam...
.WithMany(t => t.HomeMatches) - ... which has a subset of Matches by navigation HomeMatches
.HasForeignKey(m => m.HomeTeamId) ... and the associating foreign key is HomeTeamId on Match
.WillCascadeOnDelete(false); ... and don't cascade when the entity is deleted.
That's the beauty of LINQ, it's more often than not self-documenting.
Now, as for your three questions...
Only modify DbContext when you are changing your model relations or adding/deleting an entity. If you're adding, you need to do a
public DbSet Entities { get; set;
And remove it if deleting, etc.
Primary keys don't link to each other. Foreign Keys link to Primary Keys. By convention, if you have a ProjectId, a navigation object called Project and another entity called Project with a property called Id, it will automatically map ProjectId from the first entity to the Id of Project entity and give the Project entity as a navigation item to first entity when you fetch data from the DB via EF:
Only if you need non-convention based relationships. Ie, your primary keys are along the lines of "tblId" or "ParentId" instead of "Id" and "ProjectId", for example. Or you need a different kind of behaviour on some items, such as cascading on deletion for only select entities.
In EF 5, if you're using Migrations, you can alter the migration code to not implement the cascade delete:
CreateTable(
"dbo.Match",
c => new
{
MatchId = c.Long(nullable: false, identity: true),
Description = c.String(),
HomeTeamId = c.Long(nullable: false),
})
.PrimaryKey(t => t.MatchId)
.ForeignKey("dbo.Team", t => t.HomeTeamId, cascadeDelete: false)
.Index(t => t.MatchId)
.Index(t => t.HomeTeamId);
}
Or something like that.
Related
I'm not sure what I'm doing wrong here. The table "class1class2" is not being recognised.(See code below). I want to be able to use the junction table
Context
public class context: DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<class1>()
.HasMany(c => c.listofclass2).WithMany(i => i.listofclass1)
.Map(t => t.MapLeftKey("class1ID")
.MapRightKey("class2ID")
.ToTable("class1class2"));
}
}
Implementation:
context db = new context();
var r= db.class1class2;
class1class2 in the implementation code is not recognised
Yes it is not recognized because it doesn't exist. When you map many-to-many relation this way there is no class used for the junction table. It is handled transparently through your navigation properties listOfClass2 and listOfClass1.
If you want to have access to the junction table (which is useful only if the junction table contains additional data - not only foreign keys) you must create a class for that and map two one-to-many relations with this new class instead.
Here is my issue.
I have a customer table and an address table. The customer table has two foreign keys to the address table. ShippingAddressFK and BillingAddressFK
Normally I'd just have AddressFK if it was just one foreign key. But since it's two I'm not sure how to go about it.
I saw this:
Fluent Nhibernate AutoMapping -- 2 foreign keys to same table?
But I'm not sure how to translate that to the Sharp Lite Architecture override .cs file.
In the MyStore example this was the closest I could find:
public class OrderOverride : IOverride
{
public void Override(ModelMapper mapper) {
mapper.Class<Order>(map => map.Property(x => x.OrderStatus,
status => {
status.Type<OrderStatusCustomType>();
status.Column("OrderStatusTypeFk");
}));
}
}
I notice they are similar I'm just not sure how to change the solution above to fit this sort of override class in the Sharp Lite Architecture
No access to visual studio so haven't tried this out, consider psuedo code based on the code you pasted and the code in the other question you linked to:
public class CustomerOverride : IOverride
{
public void Override(ModelMapper mapper) {
mapper.Class<Customer>(map => map.Property(x => x.BillingAddress,
address => {
address.Type<Address>();
address.Column("BillingAddressFk");
}));
mapper.Class<Customer>(map => map.Property(x => x.ShippingAddress,
address => {
address.Type<Address>();
address.Column("ShippingAddressFk");
}));
}
}
I just had a look at Order override in SharpLite and this isn't fluent nhibernate, it is nhibernate code mapping which I have never used. that might not be the correct way to define multiple property overrides but hopefully the code above will work. if not change the fluentnhibernate tag to nhibernate and some1 who knows more about it should be able to help.
The example you are referring to is for mapping one of your properties to a custom type, like an Enum.
You need to map your relationship to the multiple addresses, and give it a different column name than what your conventions would.
public void Override(ModelMapper mapper)
{
mapper.Class<Customer>(map =>
map.ManyToOne(
x => x.BillingAddress,
x => x.Column("BillingAddressFk")));
mapper.Class<Customer>(map =>
map.ManyToOne(
x => x.ShippingAddress,
x => x.Column("ShippingAddressFk")));
}
Notice the ManyToOne instead of Property.
Im in a bit of a jam.
Problem
NHibernate forces me to make a foreignkey column nullable, which is a very bad idea for our database and quite ugly.
Is there a work around for this?
Situation
I have the following maps (names changed for simplicity):
public class BillMap : SequenceGeneratedIdEntityMap<Bill>
{
public BillMap()
{
Id(x => x.Id).GeneratedBy.Native("BILL_SEQ");
... (maps) ...
HasMany<Expense>(f => f.Expense)
.Schema("ACCOUNT")
.Table("EXPENSE")
.KeyColumn("BILL")
.Cascade.All();
}
}
public class ExpenseMap : SequenceGeneratedIdEntityMap<Expense>
{
public ExpenseMap ()
{
Id(x => x.Id).GeneratedBy.Native("EXPENSE_SEQ");
... (maps) ...
}
}
Using these maps I get the following from NHibernate when saving an instance of Bill:
select ACCOUNT.BILL_SEQ.nextval from dual
select ACCOUNT.EXPENSE_SEQ.nextval from dual
command 0:INSERT INTO ACCOUNT.BILL(...)
command 0:INSERT INTO ACCOUNT.EXPENSE(...)
command 0:UPDATE UPDATE.EXPENSE SET BILL = X WHERE ...
Notice 2 things here:
All id's are requested from the sequences BEFORE the inserts.
The foreignkey is not updated until AFTER the expense has been inserted.
This forces me to make the column nullable AND to allow updates on the table.
Ideally the update statement should not be necessary and handled some deep dark place inside NHB :).
This could be solved by making a bidirectional reference, but that would destroy my model :/.
I do believe this a returning issue for me (never found a good solution before). Are there anyone who knows of workaround?
Kind regards
By setting .Inverse() on your HasMany<Expense> call, NHibernate will be aware of which side is the 'parent' object. I believe that will swap the order of the inserts.
For more information:
http://wiki.fluentnhibernate.org/Getting_started#Mappings
Inverse Attribute in NHibernate
We're working with Fluent NHibernate 1.2 and our primary key is a guid saved in a nvarchar(32) column, working with Oracle 11gr2.
How can we make this work? (making an automatic conversion...)
Thanks ahead, random programmer...
UPDATE:
forgot to mention, the guid is saved WITHOUT dashes ...
Update:
You will have to implement your own IUserType to handle the dashless Guids.
You can read about it here:
http://dotnet.dzone.com/articles/understanding-nhibernate-type
The detail below is now irrelevant to the question but I'll keep it here for future reference for people to find.
Using Guids "normally"
In your entity the Id should be of type Guid:
public virtual Guid Id { get; private set; }
And in your ClassMap you should map it like this:
Id(x => x.Id)
.Column("Id")
.GeneratedBy.GuidComb();
This will use the recommended comb algorithm to generate new guids.
or
Id(x => x.Id)
.Column("Id")
.GeneratedBy.Guid();
to genertae new Guids using System.Guid
or
Id(x => x.Id)
.Column("Id")
.GeneratedBy.GuidNative();
if you want to let the database generate the Guid for you.
In doctrine, is it possible to add a WHERE clause when fetching a property of an object that corresponds to a relationship?
In terms of concept, let's say I want to retrieve only the first 3 blog posts made in the last 5 days. My "blog" object has a "posts" property which is defined as a relationship.
Update...
As some people are having some difficulties understanding what I mean by a relationship:
class Blog extends Doctrine_Record {
...
public function setUp() {
$this->hasMany("Note as Posts", array(
"local" => "blog_name",
"foreign" => "post_id",
"refClass" => "BlogPost"
));
}
}
As you can see, this is an explicit relationship as supported by doctrine. When I query using it:
$instanceOfBlog->Posts...........
I'd like to know if I can add additional clauses at that time.
Not sure I follow you, but if it's what I think then in your BlogTable class:
public function getRecentPosts()
{
$qry = self::createQuery("b")
->innerJoin("b.Posts p")
->where("p.created_at > ?", date("Y-m-d H:i:s", strtotime("-5 days")))
->orderBy("p.created_at DESC")
->limit(3);
$results = $qry->execute();
}
Is that what you were after? This is based on the created_at field in the Posts object, and assumes a relationship is defined between the Blog and Posts tables.
I may have misunderstood your question entirely however :-)