I've been going around the block a couple of times on this, so I'm taking a fresh approach. I would like to figure out if it possible to have a single entity that is on the many-side of multiple 0-to-many relationships. This is what I'm trying to do:
A Client has 0-to-many Phones
public class Client
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClientId { get; set; }
public string Name { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
A Business has 0-to-many Phones
public class Business
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int BusinessId { get; set; }
public string Name { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
And here is Phones:
public class Phone
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PhoneId { get; set; }
public string Number { get; set; }
}
Of course, the problem with the Phones property in Business/Client is that this creates FK's in Phone to both Client and Business, which clutters-up Phones.
So, I saw another poster try creating a manual join table, but it seemed to be geared to the many-side participating in one relationship:
public class ClientPhone
{
public int ClientID { get; set; }
public int PhoneID { get; set; }
public virtual Client Client { get; set; } // One Client
public virtual Phone Phone { get; set; } // One Phone
}
Should I split Phone up into ClientPhones and BusinessPhones 'normal' entities using traditional 0-to-many relationships. If someone could give me some advice on the cleanest way to to model this, it would be very appreciated.
Thanks!
I think you can model this using table per hierarchy method ,
public class Client
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClientId { get; set; }
public string Name { get; set; }
public virtual ICollection<ClientPhone> Phones { get; set; }
}
public class Business
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int BusinessId { get; set; }
public string Name { get; set; }
public virtual ICollection<BusinesPhone> Phones { get; set; }
}
public class Phone
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PhoneId { get; set; }
public string Number { get; set; }
}
public class BusinesPhone:Phone
{
}
public class ClientPhone:Phone
{
}
This will create one table for both client and business phone with a discriminator column. Then you can easily separate client and business phones.
Related
I'm trying to create next model for a web app:
A company can create customers and categories (for customers).
A customer can belong to several categories.
Several customers can belong to the same category.
Entities:
public class Company
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Customer
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int CompanyId { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int CompanyId { get; set; }
[Required]
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
Data context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Company> Companies { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Customer> Customer { get; set; }
public ApplicationDbContext()
: base(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString, throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
When I run the app and try to get a company, I get the next error:
Introducing FOREIGN KEY constraint 'FK_dbo.CustomerCategories_dbo.Categories_Category_Id' on table 'CustomerCategories' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
I don't understand why I getting this error. I think it is a many-to-many relationship which is the problem. What am I doing wrong?
I have 2 tables that I need to join with each other but I can't grasp how I can join them using a linq extension.
I can do it easy in SQL, but I'm struggling with linq.
My problem - 2 models:
public class GamesNight
{
[Key]
public int Id { get; set; }
public virtual ApplicationUser User { get; set; }
public string GamesNightTitle { get; set;}
public string GamesNightDescription { get; set; }
public string GamesNightLocation { get; set; }
public DateTime GamesNightDate { get; set; }
}
and an attendance model:
public class Attendance
{
public int Id { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual GamesNight GamesNight { get; set; }
}
Pretty simple to grasp, the user 'attends' a 'gamesnight'.
I have a view model that reads
public class UpcomingGamesNightViewModel
{
public GamesNight GamesNight { get; set; }
public bool Attending { get; set; }
}
What I am trying to achieve is a built up array of UpcomingGamesNightViewModel where the GamesNight a gamesnight and attending is where the user is attending the games night via the attending table.
Thanking you!
I'm working on a cinema application which allows users to surf through movies, cinema places and allows them to buy or reserve tickets. If a user reserved a ticket online, then the ticket must be activated in 12 hours by sellerperson who also uses the same program. I need to show the ticket informations on grid and need to make editable. Here's my database classes that must be included in query and have relationship with Sale class. (I want to select objects from Sale class which includes ti's related classes: Ticket, customer, movie, status and saloon infos.
Sale Class:
public class Sale
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey("CustomerId")]
public virtual Customer Customer { get; set; }
public int CustomerId { get; set; }
[ForeignKey("StatusId")]
public virtual Status Status { get; set; }
public int StatusId { get; set; }
public virtual Seller Seller { get; set; }
public DateTime SellDate { get; set; }
public double Price { get; set; }
[ForeignKey("TicketID")]
public virtual Ticket Ticket { get; set; }
public int TicketID { get; set; }
}
Ticket Class:
public class Ticket
{
public Ticket()
{
Seats = new List<Seat>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey("MovieId")]
public virtual Movie Movie { get; set; }
public int MovieId { get; set; }
public virtual List<Seat> Seats { get; set; }
public virtual TimeSpan SeanceTime { get; set; }
public bool IsActive { get; set; }
public DateTime BuyDate { get; set; }
[ForeignKey("SaloonId")]
public virtual Saloon Saloon { get; set; }
public int? SaloonId { get; set; }
public string TicketNumber { get; set; }
}
Customer Class:
public class Customer
{
public Customer()
{
Sales = new List<Sale>();
CreditCards = new List<CreditCard>();
}
[Key]
public int UserID { get; set; }
public virtual List<Sale> Sales { get; set; }
public virtual User User { get; set; }
[DataType(DataType.CreditCard)]
public virtual List<CreditCard> CreditCards { get; set; }
}
User Class:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
Status Class(Holds info of tickets. Bought or reserved.)
public class Status
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public bool IsRez { get; set; }
public bool IsBuy { get; set; }
public bool IsCancel { get; set; }
public bool IsPaid { get; set; }
}
Saloon Class:
public class Saloon
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public double salePrices { get; set; }
}
Movie Class:
public class Movie
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
}
I can't edit because in my select query I'm using anonymous type for selection. My query code:
var Source = entities.Sales.Where(w => w.Ticket.Saloon.CinemaPlace.ID == seller.CinemaPlace.ID).Select(s => new
{
CustomerName = s.Customer.User.Name,
CustomerSurname = s.Customer.User.Surname,
SalePrice = s.Price,
s.Status.IsBuy,
s.Status.IsCancel,
s.Status.IsPaid,
s.Status.IsRez,
MovieName = s.Ticket.BuyDate,
s.Ticket.Movie.Name,
SaloonName = s.Ticket.Saloon.Name,
s.Ticket.SeanceTime,
s.Ticket.TicketNumber
}).ToList();
RezervationsGrid.DataSource = Source3;
But in the grid, the datas couldn't be edited. Then I tried to join every single table using Linq to Entities queries but it didn't help either. Is there a way make a datasource from my related objects that allows edit option in grid? Thanks.
Anonymous types (those that you can declare via the new operator in the Select method) cannot have writable properties in .NET. That's why the grid is not editable. To take advantage of in-place editing, you need to instantiate objects of a real CLR type.
For this, you can declare a special ViewModel class with public properties that you should populate with values in the Select method using object initializer.
.Select(s => new SaleViewModel() {
CustomerName = s.Customer.User.Name,
SalePrice = Price
})
Note that you should not move the property initialisation logic to the ViewModel constructor to use it this way:
.Select(s => new SaleViewModel(s))
The object initialiser is the expression tree, which Entity Framework can translate into an SQL query. The constructor is just a method reference, so Entity Framework will reject such an expression. If you would like to use this approach, you will need to call the ToList method before the Select.
SaleViewModel can have the method accepting the DbContext class to save changes.
You also can select the Sale instances and use complex property paths in columns' field names (such as "Customer.User.Name"). This can probably help you to simplify the saving logic, as you will not need to find a model specific to a certain view model and copy modified property values.
I've seen plenty of examples not using Data Annotations and can get a one-to-one relationship working, but having difficulty with a one-to-many.
We have parts that we will randomly take sample weights on to make sure our machine house is producing to spec. The one-to-one relationship for Material will load. Having trouble with the QualityMeasurements one-to-many.
Anyone have experience with this?
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Part {
[Key]
public string PartID { get; set; }
public string PartNumber { get; set; }
[ForeignKey("MaterialID")]
public virtual Material Material { get; set; }
public int MaterialID { get; set; }
[ForeignKey("PartNumber")]
public virtual ICollection<QualityMeasurement> Qualities { get; set; }
}
public class Material {
[Key]
public int MaterialID { get; set; }
public string Title { get; set; }
public double Density { get; set; }
}
public class QualityMeasurement {
public int QualityID { get; set; }
[Key]
public string PartNumber { get; set; }
public double UnitWeight { get; set; }
}
You are having troubles because in the one-to-many relationship, the foreign key should be defined at the many side and should relate to the primary key of the one side.
Your model should be something like this:
public class Part {
[Key]
public string PartID { get; set; }
public string PartNumber { get; set; }
[ForeignKey("MaterialID")]
public virtual Material Material { get; set; }
public int MaterialID { get; set; }
public virtual ICollection<QualityMeasurement> Qualities { get; set; }
}
public class QualityMeasurement {
[Key]
public int QualityID { get; set; }
[ForeignKey("PartID")]
public virtual Part Part { get; set; }
public string PartID { get; set; }
public double UnitWeight { get; set; }
}
For example we have profile and organisation. Both have articles.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string Email { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
public class Organisation
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
In this way Article should have two kinds of parent so it should have something like parent type to be able to access a parent when you select articles directly.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
What is the best practice for storing this kind of data?
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
Possible yes but not a good idea. The underlying Database can't use a foreign key for Parentid. It would be slow.
What is the best practice for storing this kind of data?
A simple approach, with 2 Nullable parents and without CascadeOnDelete:
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public virtual Profile Profile { get; set; }
public virtual Organisation Organisation { get; set; }
}
Alternatively you could use inheritance for Article, ie class OrganisationArticle : Article {}