I have classes:
public class Game
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ID { get; set; }
[InverseProperty("Game")]
public virtual ICollection<GameMember> Members { get; set; }
//...
}
public class GameMember
{
[Key]
[Column(Order = 0)]
public Guid GameID { get; set; }
[InverseProperty("Members")]
[ForeignKey("GameID")]
public virtual Game Game { get; set; }
[Key]
[Column(Order = 1)]
public Guid UserID { get; set; }
public virtual User User { get; set; }
//...
}
As you can see, I am trying to make a simple online game. Users can join the game (in that case a new GameMember will be created) and get to the lobby. When everybody is ready, the game starts. I am wondering if there is simple way to limit the number of members. It would be great if I can just apply some attribute like [Max(4)] to ICollection<GameMember> Members.
No, that's not possible - there is no equivalent construct in SQL.
You will need to create four properties, one per allowed member.
Related
I'm testing the following scenario (code below): create a shopping mall, with shops, with cashiers, with cash desks and persons operating it.
So I've created the following classes
Table Mall
Table Shop
Table CashDesk
Table Person
Basic classes with an ID and a name.
Then I need a derived class from Person being PersonCashier or PersonCustomer.
Since everything is related, I need to create intersection tables for the many to many scenarios.
I've created the following intersection tables:
The Mall contains shops: MallShop
The shop contains CashDesks: MallShopCashDesk
And the CashDesk containing cashiers: MallShopCashDeskPersonCashier
This just doesnt feel right. Can anyone help me out on a best practice
public class Mall
{
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[Required]
public int NumberOfShopSpaces { get; set; }
}
public class Shop
{
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
}
public class CashDesk
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
public class Person
{
public int Id { get; set; }
[Required]
public string FullName { get; set; }
[Required]
public string Gender { get; set; }
}
public class PersonCashier : Person
{
[Required]
public int ShopId { get; set; }
public virtual Shop Shop { get; set; }
}
These are the base classes. How should i add a shop to a mall, a cashdesk to a shop, and a cashier to a cashdesk? (i've tried alot but posting the code would make the question look like spaghetti)
If this is code first then EF will make the relationship tables for you. You just need to add the relationships in your classes.
Exactly what they should be is not clear from your description because it depends on what relationships you want; if you want a many-many between PersonCashier and CashDesk it would be like this:
public class CashDesk
{
public List<PersonCashier> Cashiers { get; set; }
}
public class PersonCashier : Person
{
public List<CashDesk> CashDesks { get; set; }
}
(not showing all the fields for brevity)
public class Mall
{
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[Required]
public int NumberOfShopSpaces { get; set; }
List<Shop> CurrentShops { get; set; }
}
public class Shop
{
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
public List<CashDesk> CashDesks { get;set; }
}
I added the list of shops to the Mall class and CashDesks to Shops. This gives you a list of shops in the mall, and a list of cashdesks in each shop and you can follow this method for everything else you need.
If you have a database, you will have a Mall table and a Shop table.
The Shop table can have a Foreign Key to the Mall table, that's how you link them and this will work with the class structure at the top.
Or, you can have another table called MallShops where you have 2 fields, one being the MallID, the other the ShopID. This is called a Link table.
Both approaches will work with the second allowing a more complex structure with lots of Malls linked to Lots of Shops.
I would start with the database structure first, make sure you cover all you need, then you can do the classes etc in a way that makes sense. If you use something like EntityFramework then it will create all the classes for you once your database structure is ready.
I'm wondering if this scenario is possible using Entity Framework.
I am using Code-First and have defined a Domain Model as follows:
public class PrintJob
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public virtual ICollection<StockItem> stockItemstoPrint { get; set; }
}
If I leave the above to Entity Framework and add the migration updating the database without adding the Foreign key in the StockItems Model (Which I don't want as I'd rather not have a two-way link) it will create a table for me named PrintJobStockItems which will hold PrintJobID and StockItemID
- This however is fine but I was wondering if I wanted to add a property to the PrintJobStockItems with a bool 'Printed' can it be done and have logic to update that bool value? The reason is, I want to be able to set for each individual stock item whether or not it has been printed - of course not against the stockItem Model as it should not know about PrintJobs.
If I can't achieve this, it means I will have to create a print job for every stock item, which to me isn't ideal.
You can't access the behind the scenes join table, but the workaround is to create 2 one to manys:
public class StockItem
{
public int Id { get; set; } // Identity, Key is default by convention so annotation not needed
public virtual ICollection<StockItemPrintJob> StockItemPrintJobs { get; set; }
}
public class PrintJob
{
public int Id { get; set; } // Identity, Key is default by convention
public virtual ICollection<StockItemPrintJob> StockItemPrintJobs { get; set; }
}
public class StockItemPrintJob
{
[Key, Column(Order = 0)]
public int StockItemId { get; set; }
[Key, Column(Order = 1)]
public int PrintJobId { get; set; }
public bool IsPrinted { get; set; }
public virtual StockItem StockItem{ get; set; }
public virtual PrintJob PrintJob { get; set; }}
}
Then you can do something like
var item = context.StockItemPrintJob.First(sp => sp.StockItemId == stockId && sp.PrintJobId == printJobId);
item.IsPrinted = true;
context.SaveChanges();
I have the following classes:
public class ParticipantAssignment
{
[Key]
public int ParticipantId { get; set; }
public int WorksitePositionId { get; set; }
public int WorksiteId { get; set; }
public int EmployerId { get; set; }
public int ProgramId { get; set; }
public int UserId { get; set; }
public DateTime AssignDateTime { get; set; }
[Not Sure What Attribute to Use Here to Create the Relationship]
public ProgramWorksite ProgramWorksite { get; set; }
... removed ...
}
public class ProgramWorksite
{
[Key, Column(Order = 1)]
public int WorksiteId { get; set; }
[Key, Column(Order = 2)]
public int ProgramId { get; set; }
... removed ...
}
There is a 1 to 1 relationship between ParticipantAssignment and ProgramWorksite.
I'd like to be able to relate the ProgramWorksite navigation property in the ParticipantAssignment class to the ProgramWorksite class.
However, if you notice, the relationship would be based upon two fields in both classes, the WorksiteId and the ProgramId - not quite sure how to do this.
One thing to note...
The code above APPEARS to be working, but i'm not certain if its actually using the "ProgramId" in the relationship, as the relationship could be made with the WorksiteId alone - it would supply a record however it wouldn't be accurate without factoring in the ProgramId
Ok so - I was able to profile the SQL being generated using Glimpse and it appears that with the current setup above it is correctly using both the ProgramId and WorksiteId in the join.
I am wondering if anyone could advise me on how to accomplish the below using code first in EF6
If I add the Table_3 as a List on to Table_1 & Table_2 in my entities. EF automatically generates a foreign key column for both tables in Table_3 instead of recognizing that they are of the same type.
My model classes are set as follows.
public interface IParent
{
int ID { get; set; }
List<Table_3> Children { get; set; }
}
public class Table_1 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_2 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual IParent Parent { get; set; }
}
EF code first generates the below
Edit
Just to let anyone having the same problems know
I have now resolved this by changing the IParent interface to an abstract class
my classes now look like the following
[Table("ParentBase")]
public abstract class ParentBase
{
[Key]
public int ID { get; set; }
public List<Table_3> Children { get; set; }
}
[Table("Table_1")]
public class Table_1 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_2")]
public class Table_2 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_3")]
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual ParentBase Parent { get; set; }
}
with a table arrangement of
this will work although it would have been nicer if the original could have been met.
I had this problem too, and I used abstract class instead of interface from the beginning.
The problem for mine was my table_3 have two navigation properties:
one is public virtual Table_1, another is public virtual Table_2, and then EF just provisioned these extra foreign key columns,
I merged the two navigation properties into one to
public virtual parentbase {get;set;}. And then it worked. Hope this helps.
Side Note,Would suggest to add virtual keyword on public List Children { get; set; } in parentbase class, because in your previous example , it was already like that.
Thanks for posting this, i came across this issue too.
You can also do like the following where you make a 1 to many relationship between Table_1 and Table_2 with Table_3 respectively:
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
Let me know if anymore clarification is required.
So I have two model, one is Company, one is Province.
[Table("Company")]
public class Company {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public int ProvinceID { get; set; }
public ProvinceModel Province{
get {
// ????
}
}
}
public class CompanyContext : MyXsiteContext {
public DbSet<Company> Companies { get; set; }
}
Here is my Province:
[Table("Province")]
public class ProvinceModel {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
}
public class ProvinceContext : MyXsiteContext {
public DbSet<ProvinceModel> Provinces { get; set; }
}
How do I get my Company, which only save the ProvinceID, to reference the Province object so I can refer to the province.name in my view?
It seems like you want to do it similar to how the navigation properties are described here.
So in the link they describe Course -> Department but for you it is Company -> Province.
Also, as an aside, if you are going to reference Province.Name in your view you might run into a Select N+1 problem so that might be something to account for (depending on your specific use case, which I'm not 100% across, just highlighting it as a potential "thing")