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.
Related
This is done using MVC .net framework and entity framework "database first" approach. There is a many to many relationship between two tables. They are connected through third table that has combined key as id from first table and id from second table.
public class ManyToManyTable
{
[Required]
[Key, Column(Order=0)]
public int firsttableid { get; set; }
[Required]
[Key, Column(Order=1)]
public int secondtableid { get; set; }
public int something { get; set; }
[ForeignKey("firsttableid")]
public virtual FirstTable firstTable { get; set; }
[ForeignKey("secondtableid")]
public virtual SecondTable secondTable { get; set; }
}
First and Second table have some id which is primary key.
I want to create View and Controller method that enables master detail entry form for this ManyToManyTable. that would have FirstTable in Master and SecondTAble in details, and all to be saved in ManyToManyTable when button Save is pressed.
Of course, both First and Second Table have this property:
public virtual ICollection<ManyToManyTable> ManyToManyTables { get; set; }
What is the easiest way to implement cases like this one?
Thank you!
EF has a default conventions for many-to-many relationships. No need to create specific
mapping class. You have to include navigation properties in both "FirstTable" and "SecondTable" Class as shown below.
public class FirstTable
{
public FirstTable()
{
secondTableProperties = new HashSet<SecondTable>();
}
public int Id { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public virtual ICollection<SecondTable> secondTableProperties { get; set; }
}
public class SecondTable
{
public SecondTable()
{
FirstTableProperties = new HashSet<FirstTable>();
}
public int Id { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public virtual ICollection<FirstTable> FirstTableProperties { get; set; }
}
Remove mapping class from DBContext , only include above two classes. Build and run the application , EF will automatically create a Mapping table in SQL server. Usually the Mapping table contains only the primary keys of other two tables.
You can use Fluent API to take some control on the created mapping table
modelBuilder.Entity<FirstTable>()
.HasMany<SecondTable>(s => s.FirstTableProperties)
.WithMany(c => c.secondTableProperties)
.Map(cs =>
{
cs.MapLeftKey("FirstTableId");
cs.MapRightKey("SecondTableId");
cs.ToTable("ManyToManyTable");
});
If you want to work with a join table with additional properties, above mentioned many-to-many relationship won't work . In that case you will have to create two one-to-many relationships as shown below.
public class FirstTable
{
public int Id { get; set; }
public int MyProperty2 { get; set; }
public virtual ICollection<ManyToManyTable> manytomany { get; set; }
}
public class SecondTable
{
public int Id { get; set; }
public int MyProperty2 { get; set; }
public virtual ICollection<ManyToManyTable> manytomany { get; set; }
}
public ManyToManyTable
{
[Required]
[Key, Column(Order=0)]
public int firsttableid { get; set; }
[Required]
[Key, Column(Order=1)]
public int secondtableid { get; set; }
public int AdditionalProperty { get; set; }
public virtual FirstTable first { get; set; }
public virtual SecondTable Second { get; set; }
}
I saw this How to include a child object's child object in Entity Framework 5
However, I'm using MVC 5 and that doesn't seem to be working.
I have a typical Tournament, Games, Teams structure, and am trying to include Teams when I query the tournament.
I am trying to run
db.Tournaments.Include(t => t.Games.Select(g => g.Team1)).ToList();
However Team1 is coming back null. Here are my classes:
public class Tournament
{
public int TournamentId { get; set; }
public string Name { get; set; }
public virtual List<Game> Games { get; set; }
public virtual List<Standing> Standings { get; set; }
}
public class Game
{
public int GameId { get; set; }
public Location Location { get; set; }
public int LocationId { get; set; }
public virtual Team Team1 { get; set; }
public int Team1Id { get; set; }
public virtual Team Team2 { get; set; }
public int Team2Id { get; set; }
public int Team1Score { get; set; }
public int Team2Score { get; set; }
public DateTime Time { get; set; }
public Tournament Tournament { get; set; }
public int TournamentId { get; set; }
}
public class Team
{
public int TeamId { get; set; }
public string Name { get; set; }
public string Coach { get; set; }
}
Does anyone have any suggestions?
You are trying to load a single cell from the Games table in the Db, I don't think you can do this the way you are trying too.
You have your Navigation properties set to Virtual, so you should lazy load automatically when you call the property that you need. There is no need for an include statement.
All you normally need to do is iterate through the list of games in tournaments
var Tournaments = Db.Tournaments.ToList();
foreach (var game in Tournaments.Games)
{
game.Team1.TeamId;
game.Team1.Coach;
game.Team1.Name;
}
db.Tournaments.Include(t => t.Games.Team1).ToList();
This is the correct way of Including single child entities in EF5.
Given the following Domain Entities:
public class Person {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual ISet<PersonClub> Clubs { get; set; }
public Person() {
this.Clubs = new HashSet<PersonClub>();
}
}
public class Club {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual ISet<PersonClub> Members { get; set; }
public Club() {
this.Persons = new HashSet<PersonClub>();
}
}
public class PersonClub {
public virtual Guid Id { get; set; }
public virtual Person Person { get; set; }
public virtual Club Club { get; set; }
}
and DTO's:
public class PersonDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public ISet<ClubDTO> Clubs { get; set; }
public PersonDTO() {
this.Clubs = new HashSet<ClubDTO>();
}
}
public class ClubDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public ISet<PersonDTO> Members { get; set; }
public ClubDTO() {
this.Members = new HashSet<PersonDTO>();
}
}
Is there a way to map these Domain Entities to their DTO's? The problem is that PersonDTO needs a collection of ClubDTO, not just Club, and vice versa for ClubDTO needing a collection of PersonDTO and not just Person.
This design causes an infinite loop when trying to map PersonClub -> PersonDTO and PersonClub -> ClubDTO:
Mapper.CreateMap<Person, PersonDTO>();
Mapper.CreateMap<Club, ClubDTO>();
Mapper.CreateMap<PersonClub, ClubDTO>()
.ConvertUsing(x => Mapper.Map<Club, ClubDTO>(x.Club));
Mapper.CreateMap<PersonClub, PersonDTO>()
.ConvertUsing(x => Mapper.Map<Person, PersonDTO>(x.Person));
I understand why this is happening, but am curious to how others handle this situation.
In this situation when calling Mapper.Map<Person, PersonDTO>(personEntity), it isn't necessary to load all members of all clubs that a person is a part of (The relationship doesn't need to go that deep ever). Same is true for Mapper.Map<Club, ClubDTO>(clubEntity).
Is this a design flaw? Would it be better to not have a PersonClub domain entity and just have public virtual ISet<Club> Clubs { get; set; } as the ManyToMany relationship? Although I believe this would still cause the circular reference.
Any input is appreciated.
I want to join two below model class with entity framework in controller for present factor in accounting system in a view
<pre>
namespace AccountingSystem.Models
{
public class BuyFactor
{
public int BuyFactorId { get; set; }
public DateTime CreateDate { get; set; }
public string Seller { get; set; }
public string Creator { get; set; }
public decimal SumAllPrice { get; set; }
public ICollection<BuyFactorDetail> BuyFactorDetails { get; set; }
}
}
namespace AccountingSystem.Models
{
public class BuyFactorDetail
{
public int BuyFactorDetailId { get; set; }
public int Number { get; set; }
public string Description { get; set; }
public decimal SumPrice { get; set; }
public int BuyFactorId { get; set; }
public virtual BuyFactor BuyFactor { get; set; }
public virtual Commodity Commodity { get; set; }
}
}
</pre>
Create a new Model
public class JointModel
{
public BuyFactor BuyFactor {get; set;}
public BuyFactorDetail BuyFactorDetail {get; set;}
}
Just create another model then calls the other model in there
public class ParentModel
{
public BuyFactor BuyFactor {get; set;}
public BuyFactorDetail BuyFactorDetail {get; set;}
}
So when you will call it in view
#model IEnumerable<AccountingSystem.Models.ParentModel>
#Html.DisplayNameFor(model => model.BuyFactor.Creator)
Best way define Model as a Property in Main Model
For example
public class BuyFactor
{
public int BuyFactorId { get; set; }
public DateTime CreateDate { get; set; }
public string Seller { get; set; }
public string Creator { get; set; }
public decimal SumAllPrice { get; set; }
public ICollection<BuyFactorDetail> BuyFactorDetails { get; set; }
public BuyFactorDetail BuyFactorEntity {get;set;}
}
Assign value in BuyFactorEntity and use as Model.BuyFactorEntity.BuyFactorDetailId
Use a Linq join query like
var query = (from b in context.BuyFactors
join d in context.BuyFactorDetail
on
..
select new
{
BuyFactorId = b.BuyFactorId,
....
BuyFactorDetailId = d.BuyFactorDetailId,
...
..
}));
Your BuyFactor already contains the BuyFactorDetail collection. You sure the entities are 1:N relationship with each other?
You can use the BuyFactor as model and could use the BuyFactorDetails propertu of the BuyFactor entity.
Use ViewBag in controller to assign respective objects for both.
ViewBag.BuyFactor= BuyFactor;
ViewBab.BuyFactorDetail = BuyFactorDetail;
To use it in view you will have to typecast them back.
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.