There are three entities:
class A
{
public int Id { get; set; }
public string Z { get; set; }
public virtual B Bc { get; set; }
public virtual C Cc { get; set; }
}
class B
{
public int Id { get; set; }
public string X { get; set; }
public virtual A Ac { get; set; }
}
class C
{
public int Id { get; set; }
public string Y { get; set; }
public virtual A Ac { get; set; }
}
I would like the 'A' class to be in a one-to-one connection with the 'B' class or 'C' class but only with one of them.
The one-to-one connections are ready among tables in the database.
I tried to use fluent mapping to establish their relationship but I always got error when I wanted to insert A:
A referential integrity constraint violation occurred: The property value(s) of 'A.ID' on one end of a relationship do not match the property value(s) of 'B.ID' on the other end.
modelBuilder.Entity<A>()
.HasOptional(x => x.B)
.WithRequired();
modelBuilder.Entity<A>()
.HasOptional(x => x.C)
.WithRequired();
OR
modelBuilder.Entity<B>()
.HasRequired(t => t.A)
.WithOptional(t => t.B);
modelBuilder.Entity<C>()
.HasRequired(t => t.A)
.WithOptional(t => t.C);
What is the solution, please?
EDIT:
I save A.
B.ID = A.ID
I save B.
Related
I have a viewmodel that includes two classes.
These classes are in relation with another classes , one-to-many and one-to-one relations.
How can I pass data from viewmodel into tables that thay have relation with another tables?
for example:
public class A
{
public int a_id { get; set; }
public string a_field1 { get; set; }
...
//one-to-many with B
public virtual ICollection<B> Bs { get; set; }
//one-to-one with D
public virtual D Ds { get; set; }
}
public class B
{
public int B_id { get; set; }
public string B_field1 { get; set; }
...
public int a_id { get; set; }
public int c_id { get; set; }
// one-to-many with A , C
public virtual A As { get; set; }
public virtual C Cs { get; set; }
}
public class C
{
public int C_id { get; set; }
public string C_field1 { get; set; }
...
// one-to-many with B
public virtual ICollection<B> Bs { get; set; }
// one-to-one with E
public virtual E Es { get; set; }
}
My viewmodel is maked from A and B.
How to add infos ,into A that has a collection from B and virtual instance from D?
Or in B that has virtual instance from A and C?
Do I change my viewmodel?
Please guide and advise me.
i find my answer:
when you want to make view model from classes like above ,you don't need use virtual collection or virtual property in view model.
you should use just properties that you need.
in this example ,your view model from A and B this will be:
public class VM_A_B
{
public int A_id { get; set; }
public int A_Field1 { get; set; }
public int b_id { get; set; }
public int b_Field1 { get; set; }
//no need any virtual collection or virtual property
}
Good Luck.
I am not sure how to get the results from joining the tables in controllers.
There're 3 tables 'Groups' 'Users' 'GroupUser' (bridge table).
public class Group
{
[Key]
public int GroupID { get; set; }
public string Group_Name { get; set; }
public ICollection<User> Users { get; set; }
}
public class User
{
[Key]
public int UserID { get; set; }
public string User_Name { get; set; }
public ICollection<Group> Groups { get; set; }
}
I also have this EFContext class
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Group>()
.HasMany(g => g.Users)
.WithMany(u => u.Groups)
.Map(m =>
{
m.MapLeftKey("UserID");
m.MapRightKey("GroupID");
m.ToTable("GroupUSer");
});
Do I also need to build a GroupUser class (to represent the GroupUser bridge table)?
Then how do I get the results when joining the 3 tables to get list of groups and users?
GroupViewModel model = new GroupViewModel
{
Groups = .... // this should be a linq statement that get results
that contains all groups and users
};
The equal sql statemen would be
select *
from Group g
join GroupUser gu on g.GroupID=gu.GroupID
join User u on u.UserID=gu.UserID
No, intermediate class is not needed.
The main point of an ORM (Object-Relational Mapper, which is what Entity Framework is) is to abstract away the database and let you work in a pure object-oriented way. Intermediate tables are definitely a database term and are not needed here.
The only reason I can think of that may lead you to create an intermediate class is when you need a "payload" (an extra meta-data) on the association. For example:
public class User
{
public int Id { get; set; }
public int Email { get; set; }
public virtual ICollection<Account> Accounts { get; set; }
}
public class Account
{
public int Id { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Now, if you want the user-to-account association to define whether the association is of "Own the account" type (Administrator), you can do something like:
public class User
{
public int Id { get; set; }
public int Email { get; set; }
public virtual ICollection<AccountUserAssociation> Accounts { get; set; }
}
public class Account
{
public int Id { get; set; }
public virtual ICollection<AccountUserAssociation> Users { get; set; }
}
public class AccountUserAssociation
{
public virtual User User { get; set; }
public virtual Account Account { get; set; }
public AssociationType AssociationType { get; set; }
}
public enum AssociationType { Regular, Administrator }
Before me, one developer used Entity Framework code first. I am not good at EF code first, so when I try to insert data, my code gives this error:
Entities in 'TourismContext.HotelOrders' participate in the 'HotelOrder_Order' relationship. 0 related 'HotelOrder_Order_Target' were found. 1 'HotelOrder_Order_Target' is expected.
This is my insert code:
var hotelOrdersInsert = new Data.Entities.HotelOrder
{
OrderId = odr.ID // this gives 7
HotelID = 13,
StartAt = DateTime.Now, // arrivalDate,
EndAt = DateTime.Now, // departureDate,
PaymentTypeID = 1,
PaymentStatusID = 1,
PaymentIdentifier = "a",
TotalRate = Convert.ToDecimal(total),
CurrencyID = 1
};
db.HotelOrders.Add(hotelOrdersInsert);
db.SaveChanges();
And this is my HotelOrder class:
public class HotelOrder
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
public int HotelID { get; set; }
public int OrderId { get; set; }
// other properties
public virtual Order Order { get; set; }
public virtual Hotel Hotel { get; set; }
}
This is my Order class:
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public virtual HotelOrder HotelOrder { get; set; }
}
Where can I find the relationship between the order and hotel order models?
You must write this relation as follows:
public class HotelOrder
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
public int HotelID { get; set; }
[ForeignKey("Order")]
public int OrderId { get; set; }
public Order Order { get; set; }
[ForeignKey("Hotel")]
public int HotelId { get; set; }
public Hotel Hotel { get; set; }
}
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public List<HotelOrder> HotelOrders { get; set; }
}
The problem is the relationship between HotelOrder and Order. It's most likely that you have a 1 to 1 relation. Meaning, Every HotelOrder must have an Order.
The relation is probably defined in the so called fluent API. Check the OnModelCreating(DbModelBuilder) function override of your class derived from DbContext. It probably states something like this:
modelBuilder.Entity<HotelOrder>().HasRequired(hotel_order => hotel_order.Order).WithRequiredPrincipal();
This tells EntityFramework that every HotelOrder must have an Order.
Alternatively, the relationship could be defined as DataAnnotations. Like Elvin Mammadov explained in his answer.
At this point the solution becomes obvious. You need to add an instance of Order to your HotelOrder instance before adding it to db.HotelOrders.
i wanna add and an entity and get its identity before savechanges() and set it as a foreign key of another entity before savechanges in entity framework code first. is it possible?
first model
public class A
{
int AId { get; set; }
string name { get; set; }
}
second model
public class B
{
int BId { get; set; }
int AId { get; set; }
string name { get; set; }
}
and.....
db.As.Add(A);
b.AId = A.Aid;
db.savechanges();
is there any article which explains how it works?
Declare a property of type A in B.
public class A
{
int AId { get; set; }
string name { get; set; }
}
public class B
{
int BId { get; set; }
virtual A A { get; set; }
int AId { get; set; }
string name { get; set; }
}
Then assign the instance of A to that navigational property. EF will determine the insert/update order of entities resolve the FKs.
b.A = a;
db.As.Add(a);
db.savechanges();
I'm trying to create a list of train journeys (among other things) in MVC, using code first Entity Framework and wondered how I could map foreign keys for the stations. The Journey model/table will have a DepartureStationID and an ArrivalStationID which will be foreign keys linking to one table/model, called Station.
Here is the code for both these models:
public class Station
{
public int StationID { get; set; }
public string StationName { get; set; }
public string StationLocation { get; set; }
}
public class Journey
{
public int JourneyID { get; set; }
public int DepartureID { get; set; }
public int ArrivalID { get; set; }
public int OperatorID { get; set; }
public string JourneyCode { get; set; }
public virtual Operator Operator { get; set; }
public virtual Station DepartureStation { get; set; }
public virtual Station ArrivalStation { get; set; }
}
There is another foreign key value in there, namely Operator and that has mapped successfully, but the departure and arrivals haven't, and return null values in the view: (#Html.DisplayFor(modelItem => item.DepartureStation.StationName).
When I looked in the database, there had been two additional fields created by EF:
DepartureStation_StationID
ArrivalStation_StationID
And the SQL relationship was between the station table and the two fields above, rather than DepartureID and ArrivalID
So, my question is - Do I need to do something different in the model when referencing the same table for two fields? I don't know why those additional fields were added so I presume I've set up the model incorrectly.
Thanks
For completeness, here's the same thing with fluent configuration.
public class MyDb : DbContext
{
public DbSet<Journey> Journeys { get; set; }
public DbSet<Operator> Operators { get; set; }
public DbSet<Station> Stations { get; set; }
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<Journey>()
.HasRequired(j => j.DepartureStation)
.WithMany()
.HasForeignKey(j => j.DepartureID);
builder.Entity<Journey>()
.HasRequired(j => j.ArrivalStation)
.WithMany()
.HasForeignKey(j => j.ArrivalId);
// ... Same thing for operator ...
base.OnModelCreating(builder);
}
}
Edit: To address your above comment about the cascade delete, you can add .WillCascadeOnDelete(false) after .HasForeignKey() and that might help (although you'll then have to delete Journey records manually)
Add the folowing attributes on your navigation properties :
public class Journey
{
public int JourneyID { get; set; }
public int DepartureID { get; set; }
public int ArrivalID { get; set; }
public int OperatorID { get; set; }
public string JourneyCode { get; set; }
[ForeignKey("OperatorID")]
public virtual Operator Operator { get; set; }
[ForeignKey("DepartureID")]
public virtual Station DepartureStation { get; set; }
[ForeignKey("ArrivalID")]
public virtual Station ArrivalStation { get; set; }
}
And of course you need to regenerate your database in order to apply the new configuration.
Hope this will help.