Extend Code First Model with a navigation property - c#

Tried to separate my customer management playground solution into modules with following logics:
A Customer might have Orders.
An Order has OrderDetails which might correspond to InvoiceDetails which should be part of an Invoice.
Order is part of CustomerManagement project and Invoice is in separate project which is referenced in CustomerManagement.
I have defined two dbcontexts one for CustomerManagement and other one for invoice management, the later derives from the first one, that should allow me to use the entities defined in CustomerManagement when dealing with invoices, f.e. the following silly navigation Invoice.InvoiceDetails.First().OrderDetail.Order.Customer.
CustomerManagement model defines customer, his phones and other data;
Invoice management model defines invoice, invoice details and inherits orders to add a new navigation property between OrderDetail and InvoiceDetail, now since EF6 doesn't like the use of the same simple named types in one model I had to call the extending type FI_OrderDetail. Here I want to be able to navigate like this db.OrderDetails.First(od => od.Id == id).InvoiceDetail. Now, I want to prevent awkward searches like db.InvoiceDetails.First(invd => invd.OrderDetail.Id == id)
And here arises the first question, since I don't add any real data I want to use the same table, but EF will seek for a discriminator, but there is no need for it since effectively it is the same entity, what should I do? I can use Ignore<T> of DbModelBuilder, but then all other entities that use that ignored type for navigation purposes won't find it. Is there some other approach I should use or I miss something in my scenario?
Below are sample models:
namespace CustomerManagement
{
public partial class Customer
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Given Name")]
public string GivenName { get; set; }
[Required]
[Display(Name = "Surname")]
public string Surname { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual IList<Phone> Phones { get; set; }
}
public class Order
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
public string CustomerId { get; set; }
[Required]
[Display(Name = "Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd hh:mm}", ApplyFormatInEditMode = true)]
public DateTime? Date { get; set; }
public string Notes { get; set; }
[InverseProperty("Orders")]
public virtual Customer Customer { get; set; }
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
{
[Key]
public int Id { get; set; }
[Required]
public int OrderId { get; set; }
[Required]
public decimal Price { get; set; }
[Required]
public string Description { get; set; }
[ForeignKey("OrderId")]
public virtual Order Order { get; set; }
}
public class CMDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Phone> Phones { get; set; }
}
}
namespace Finance
{
public class Invoice
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
[Display(Name = "Customer ID")]
public int CustomerId { get; set; }
[Required]
[Display(Name = "Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd hh:mm}", ApplyFormatInEditMode = true)]
public DateTime Date { get; set; }
[ForeignKey("CustomerId")]
public virtual CustomerManagement.Customer Customer { get; set; }
public virtual ICollection<InvoiceDetail> InvoiceDetails { get; set; }
}
public class InvoiceDetail
{
[Key]
[Column("Id", TypeName = "int")]
public int Id { get; set; }
[Required]
public int InvoiceId { get; set; }
public string Details { get; set; }
public decimal Price { get; set; }
[ForeignKey("InvoiceId")]
public virtual Invoice Invoice { get; set; }
public virtual FI_OrderDetail OrderDetail { get; set; }
}
public class FI_OrderDetail : CustomerManagement.OrderDetail
{
public virtual ICollection<InvoiceDetail> InvoiceDetails { get; set; }
}
public class FIDbContext : CustomerManagement.CMDbContext
{
public new DbSet<FI_OrderDetail> OrderDetails { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InvoiceDetail> InvoiceDetails { get; set; }
}
}

Related

One to many relationship crud

I am currently working with Asp.NEt Core 6. I would like to create CRUD with one to many relationship between two Models (Staffs and Tax). The idea is to have one staff have several tax entries.
Staff Model
namespace Join.Models
{
public class Staff
{
[Key]
public int staffid { get; set; }
public string staffname { get; set; }
public int salary { get; set; }
}
}
Tax Model
namespace Join.Models
{
public class Paye
{
public int Id { get; set; }
[DataType(DataType.Date)]
public DateTime CreatedDate { get; set; }
public int amount { get; set; }
[Required]
[ForeignKey("Staff")]
public int staffid { get; set; }
public virtual Staff Staff { get; set; }
}
}
I do not know how to code the controllers and views
I think it should be like this:
namespace Join.Models
{
public class Staff
{
[Key]
public int staffid { get; set; }
public string staffname { get; set; }
public int salary { get; set; }
public virtual List<Paye> taxEntries {get; set; }
}
}
namespace Join.Models
{
public class Paye
{
public int Id { get; set; }
[DataType(DataType.Date)]
public DateTime CreatedDate { get; set; }
public int amount { get; set; }
[Required]
public int staffid { get; set; }
[ForeignKey("staffid")]
public virtual Staff Staff { get; set; }
}
}
And i would recommend you make a migration after these changes

Creating a one-to-many relationship EF Core - update-database fail

I wants to create a one-to-many relationship.
The plan is as follows: One Customer can have multiple Bikes. Below I present the data models.
Bike Model
public class Bike
{
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(50)]
public string Brand { get; set; }
[Required]
public int Size { get; set; }
[Required]
[MaxLength(200)]
public string Description { get; set; }
[Required]
[MaxLength(50)]
public string Model { get; set; }
[ForeignKey("CustomerID")]
public Guid CustomerID { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime AddedBike { get; set; }
}
Customer Model
public class Customer
{
[Key]
public Guid Id { get; set; }
[StringLength(50, MinimumLength = 3)]
[Required]
public string Name { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string Surname { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DisplayName("Telephone")]
public string TelephoneNumber { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime DateTimeAdd { get; set; }
[DataType(DataType.DateTime)]
[DisplayName("Last Update Customer")]
public DateTime EditDate { get; set; }
public virtual ICollection<Bike> Bike { get; set; }
}
DBContext
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Bike> Bikes { get; set; }
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Migration is going well. However, update-database causes this error:
PM> update-database
Build started...
Build succeeded.
System.InvalidOperationException: There is no entity type mapped to the table 'Bikes' used in a data operation. Either add the corresponding entity type to the model or specify the column types in the data operation.
...
There is no entity type mapped to the table 'Bikes' used in a data operation. Either add the corresponding entity type to the model or specify the column types in the data operation.
Where is the mistake I am making?
Finally, it worked. I finally deleted all migrations, created a new migration and updated the database.
I then added the relationships in the models, did the migration again and updated the database and it worked.
My models look like this
Bike.cs
public class Bike
{
[Key]
public Guid Id { get; set; }
[Required]
[MaxLength(50)]
public string Brand { get; set; }
[Required]
public int Size { get; set; }
[Required]
[MaxLength(200)]
public string Description { get; set; }
[Required]
[MaxLength(50)]
public string Model { get; set; }
public Guid CustomerID { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime AddedBike { get; set; }
[ForeignKey("CustomerID")]
public Customer Customer { get; set; }
}
Customer.cs
public class Customer
{
[Key]
public Guid Id { get; set; }
[StringLength(50, MinimumLength = 3)]
[Required]
public string Name { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string Surname { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DisplayName("Telephone")]
public string TelephoneNumber { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime DateTimeAdd { get; set; }
[DataType(DataType.DateTime)]
[DisplayName("Last Update Customer")]
public DateTime Edit { get; set; }
public virtual ICollection<Bike> Bike { get; set; }
}

Entity Framework 6 table with many foreign keys each pointing to different tables

I have Country, City, Region and "Account Address" tables.
I want to create foreign key columns in "Account Address" pointing to Country, City, Region tables.
I have this code but it throws an error on creating database
The property \u0027Account_Id\u0027 cannot be configured as a
navigation property. The property must be a valid entity type and the
property should have a non-abstract getter and setter. For collection
properties the type must implement
After New Edit
public class Cities
{
[Key]
public int City_Id { get; set; }
public string City_name { get; set; }
public int Country_Id { get; set; }
[ForeignKey("Country_Id")]
public Countries countries { get; set; }
}
public class Region
{
[Key]
public int Region_Id { get; set; }
public string Region_name { get; set; }
public int City_Id { get; set; }
[ForeignKey("City_Id")]
public Countries countries { get; set; }
}
public class Accounts
{
[Key]
public int Account_Id { get; set; }
public string Fullname { get; set; }
public string Email { get; set; }
public string password { get; set; }
public int Cell_phone { get; set; }
public string Role { get; set; }
public int? estate_office_Id { get; set; }
[ForeignKey("estate_office_Id")]
public Estate_office estate_office { get; set; }
public List<Ads> ads { get; set; }
}
public class Account_address
{
[Key]
public int Id { get; set; }
[ForeignKey("Account_Id"), Column(Order = 0)]
public int Account_Id { get; set; }
[ForeignKey("Country_Id"), Column(Order = 1)]
public int Country_Id { get; set; }
[ForeignKey("City_Id"), Column(Order = 2)]
public int City_Id { get; set; }
[ForeignKey("Region_Id"), Column(Order = 3)]
public int Region_Id { get; set; }
public Accounts accounts { get; set; }
public Countries countries { get; set; }
public Cities cities { get; set; }
public Region region { get; set; }
}
You need to define public properties as shown below on the Account_address class.Then only EF will know how to map those navigation properties correctly.
public class Account_address
{
......
......
public Accounts accounts { get; set; } //like this
public Countries countries { get; set; } //like this
public Cities cities { get; set; } //like this
public Region region { get; set; } //like this
}
Update :
Hence you're not using singular naming convention for the classes,you have encountered this issue.Either you have to change the name of classes as singular or need to change the navigational property names a shown below.You have to do this for all the places.Here I have shown only for the Accounts class related navigational property.
[ForeignKey("Accounts_Id"), Column(Order = 0)]
public int Accounts_Id { get; set; }
My Advice is to follow the basic naming conventions.Then you can avoid lot of above kind of weird errors.

ASP.NET Relation between two tables

I'm new in Asp.Net and Entity Framework and i have a little issue.
I know u can help me , because its simple and i only know how to do it in PHP XD
I Have 2 models
public class Suppliers
{
public int ID { get; set; }
public int ID_Guard { get; set; }
public string Supplier{ get; set; }
public string Description { get; set; }
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd hh:mm tt}", ApplyFormatInEditMode = true)]
public DateTime Enter { get; set; }
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd hh:mm tt}", ApplyFormatInEditMode = true)]
public DateTime Exit { get; set; }
public virtual Guard Guard { get; set; }
}
public class Guard
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Suppliers> Suppliers{ get; set; }
}
controller
public class SuppliersController : Controller
{
private SuppliersContext db = new SuppliersContext();
public ActionResult Index()
{
return View(db.Suppliers.ToList());
}
}
And i wanna pass to the view the 2 table data and relate it
When i go to index show me all the suppliers data and show the Guard name( the person who registered the supplier enter and exit)
Well its solved
var results = from c in db.Suppliers
join cn in db.Guard on c.ID_Guard equals cn.ID
where (c.ID_Guard == cn.ID)
select new Models.MyViewModel{ Name= cn.Name, ID = c.ID, Supplier=c.Supplier, Description=c.Description, Enter=c.Enter, Exit=c.Exit};
follow the below code it works and seems same like yours also i added the link hope you find It helpful
public class Product
{
public Product() { Id = Guid.NewGuid(); }
public Guid Id { get; set; }
public string ProductName { get; set; }
public virtual ProductCategory ProductCategory { get; set; }
}
public class ProductCategory
{
public int Id { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
/////view model///
public class ProductViewModel
{
public Guid Id { get; set; }
[Required(ErrorMessage = "required")]
public string ProductName { get; set; }
public int SelectedValue { get; set; }
public virtual ProductCategory ProductCategory { get; set; }
[DisplayName("Product Category")]
public virtual ICollection<ProductCategory> ProductCategories { get; set; }
}
follow the below tutorial
relationship model
for basic join use below query
var dealercontacts = from contact in table1
join table2 in table2 on contact.Id equals another.ID
select contact;

Complex relationship mappings in entity framework

I am building a reservation system. I have users in roles('admin', 'client', 'employee', 'student').
Each reservation must be associated with a user of role client, it might be assigned to user of role employee and might also be assigned to user of role student.
So in my reservation class I have properties of type User and I have marked them with [ForeignKey("AnytypeId")] attribute to hint EF for relations.
I have seen code like this at http://blog.stevensanderson.com/2011/01/28/mvcscaffolding-one-to-many-relationships/
public class Reservation
{
public int ReservationID
{
get;
set;
}
[Required(ErrorMessage="Please provide a valid date")]
public DateTime ReservationDate
{
get;
set;
}
public DateTime ReservationEnd { get; set; }
public DateTime EntryDate
{
get;
set;
}
public DateTime UpdatedOn
{
get;
set;
}
public decimal Ammount
{
get;
set;
}
public decimal? Discount { get; set; }
[DataType(DataType.MultilineText)]
public string ServiceDetails { get; set; }
[DataType(DataType.MultilineText)]
public string Remarks { get; set; }
public string VoucherNumber { get; set; }
public int ServiceID
{
get;
set;
}
public Service Service
{
get;
set;
}
public string EmployeeId { get; set; }
[ForeignKey("EmployeeId")]
public User Employee { get; set; }
public string ClientId { get; set; }
[ForeignKey("ClientId")]
public User Client { get; set; }
public string StudentId { get; set; }
[ForeignKey("StudentId")]
public User Student { get; set; }
}
public class User
{
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
//public Guid UserId { get; set; }
[Key]
[Required(ErrorMessage = "User Name is required")]
[Display(Name = "User Name")]
[MaxLength(100)]
public string UserName { get; set; }
[Required]
[MaxLength(64)]
public byte[] PasswordHash { get; set; }
[Required]
[MaxLength(128)]
public byte[] PasswordSalt { get; set; }
[Required(ErrorMessage = "Email is required")]
[DataType(DataType.EmailAddress)]
[MaxLength(200)]
public string Email { get; set; }
[MaxLength(200)]
public string Comment { get; set; }
[Display(Name = "Approved?")]
public bool IsApproved { get; set; }
[Display(Name = "Crate Date")]
public DateTime DateCreated { get; set; }
[Display(Name = "Last Login Date")]
public DateTime? DateLastLogin { get; set; }
[Display(Name = "Last Activity Date")]
public DateTime? DateLastActivity { get; set; }
[Display(Name = "Last Password Change Date")]
public DateTime DateLastPasswordChange { get; set; }
public string address { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Phone { get; set; }
public bool? IsActive { get; set; }
public int? ClientTypeID { get; set; }
public virtual ClientType ClientType { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public DateTime? PackageValidity { get; set; }
public virtual ICollection<Reservation> Reservations { get; set; }
}
public class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
this.HasMany(u => u.Roles)
.WithMany(r => r.Users)
.Map(m =>
{
m.ToTable("RoleMemberships");
m.MapLeftKey("Username");
m.MapRightKey("RoleName");
});
}
}
Now as I run my mvc3 EF code first app database created for me on the fly with following ERD and edmx model.
Now few problems that I am having:
1. When I am listing all the users of role clients their reservation property is showing always 0 even if their are reservations available in database.
2. If I am trying to delete a user of role client who have reservation in database I get following error.
The DELETE statement conflicted with the REFERENCE constraint "Reservation_Client". The conflict occurred in database "CRSDB", table "dbo.Reservations", column 'ClientId'.
The statement has been terminated.
I checked the realtions in ERD and edmx model their is no cascade delete applied to them. How can I instruct EF to delete all the reservations when deleting user of role client but not for users of role employee or student.
This code does the trick
public class Reservation
{
public int ReservationID
{
get;
set;
}
[Required(ErrorMessage="Please provide a valid date")]
public DateTime ReservationDate
{
get;
set;
}
public DateTime ReservationEnd { get; set; }
public DateTime EntryDate
{
get;
set;
}
public DateTime UpdatedOn
{
get;
set;
}
public decimal Ammount
{
get;
set;
}
public decimal? Discount { get; set; }
[DataType(DataType.MultilineText)]
public string ServiceDetails { get; set; }
[DataType(DataType.MultilineText)]
public string Remarks { get; set; }
public String PaymentMethod { get; set; }
public string VoucherNumber { get; set; }
public int ServiceID
{
get;
set;
}
public virtual Service Service
{
get;
set;
}
public string EmployeeID { get; set; }
[ForeignKey("EmployeeID")]
public virtual User Employee { get; set; }
public string ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual User Client { get; set; }
public string StudentID { get; set; }
[ForeignKey("StudentID")]
public virtual User Student { get; set; }
}
public class ReservationMap : EntityTypeConfiguration<Reservation>
{
public ReservationMap()
{
this.HasOptional(r => r.Client).WithMany().WillCascadeOnDelete(true);
this.HasOptional(r => r.Employee).WithMany().WillCascadeOnDelete(false);
this.HasOptional(r=>r.Student).WithMany().WillCascadeOnDelete(false);
}
}

Categories

Resources