Creating a Key Table and Domain Models - c#

All,
I need to add a domain class for a new key table that relates a table of club members ([dbo].NewClubProspect) to emails ([dbo].NewClubEmail) sent to them.
I am not sure how to set this up in the domain classes.
Question
Need to annotate the key table (NewClubProspectNewClubEmail) Since both properties are foreign keys, not sure if I need an actual primary key, too? How do I annotate this?
Here is a diagram of how the tables relate. The table on the bottom of the diagram (NewClubProspectNewClubEmail) is the new table that I need to create in the database and in code, in a domain class.
Here are my domain classes (chopped down for brevity)
public class NewClub
{
public NewClub()
{
NewClubProspects = new List<NewClubProspect>();
NewClubEmails = new List<NewClubEmail>();
}
public int Id { get; set; }
public string NewClubName { get; set; }
public string NewClubLocation { get; set; }
public string NewClubType { get; set; }
public string NewClubCity { get; set; }
public string NewClubState { get; set; }
public string NewClubCountry { get; set; }
public virtual List<NewClubProspect> NewClubProspects { get; set; }
public virtual List<NewClubEmail> NewClubEmails { get; set; }
}
public class NewClubProspect
{
[Key]
public int Id { get; set; }
//Foreign Key
public int NewClubId { get; set; }
public bool IsConverted { get; set; }
public string ProspectFirstName { get; set; }
public string ProspectLastName { get; set; }
public string ProspectEmail { get; set; }
public virtual NewClub NewClub { get; set; }
public virtual List<NewClubEmail> NewClubEmails { get; set; }
}
public class NewClubEmail
{
//Primary key
[Key]
public int Id { get; set; }
//Foreign Key
public int NewClubId { get; set; }
public string Subject { get; set; }
public virtual List<NewClubProspect> Recipients { get; set; }
public string Body { get; set; }
public DateTime CreateDate { get; set; }
public DateTime ModifiedDate { get; set; }
public DateTime? SentDate { get; set; }
public NewClub NewClub { get; set; }
public NewClubEmail()
{
Recipients = new Collection<NewClubProspect>();
}
}
//---------------------------------------------------------
// Not sure what to do here. They are both foreign keys
//---------------------------------------------------------
public class NewClubProspectNewClubEmail
{
public int NewClubEmail_Id {get; set;}
public int NewClubProspect_Id {get; set;
}

Just mark both as Key:
[Key]
public int NewClubEmail_Id {get; set;}
[Key]
public int NewClubProspect_Id {get; set;}

Related

DbUpdateException when adding item to Entity Framework Context

I have the following two classes:
public class Record
{
public int RecordId { get; set; }
public DateTime? InsertDate { get; set; } = DateTime.Now;
public DateTime BookingDate { get; set; }
public string AmountTypeName { get; set; }
public double? Amount { get; set; }
public string BookingAccountID { get; set; }
public string AccountCurrency { get; set; }
public string ClientCurrency { get; set; }
public string AffectsBalance { get; set; }
public double? AmountAccountCurrency { get; set; }
public string AmountClientCurrency { get; set; }
public int UnifiedInstrumentCode { get; set; }
public InstrumentInfo InstrumentInfo { get; set; }
}
public class InstrumentInfo
{
[Key]
public int UnifiedInstrumentCode { get; set; }
public ICollection<Record> Record { get; set; }
public string AssetType { get; set; }
public int UnderlyingInstrumentUic { get; set; }
public string UnderlyingInstrumentSubType { get; set; }
public string InstrumentSymbol { get; set; }
public string InstrumentDescription { get; set; }
public string InstrumentSubType { get; set; }
public string UnderlyingInstrumentAssetType { get; set; }
public string UnderlyingInstrumentDescription { get; set; }
public string UnderlyingInstrumentSymbol { get; set; }
}
that I want to use as my context for EF6.
I defined the context the following way:
public class TransactionsContext: DbContext
{
public DbSet<Record> Records { get; set; }
public DbSet<InstrumentInfo> InstrumentInfos { get; set; }
public TransactionsContext()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<TransactionsContext>(null);
base.OnModelCreating(modelBuilder);
}
}
If I run a test against it that shall add and InstrumentInfo object to the DB
[TestMethod]
public void AddInstrumentInfo_Added_IsTrue()
{
InstrumentInfo info = FakeFactory.GetInstrumentInfo();
using (var ctx = new TransactionsContext())
{
ctx.InstrumentInfos.Add(info);
ctx.SaveChanges();
}
}
I get the following exception:
SqlException: Cannot insert the value NULL into column
'UnifiedInstrumentCode', table
'TransactionsContext.dbo.InstrumentInfoes'; column does not allow
nulls. INSERT fails. The statement has been terminated.
I tried all different scenarios that I found here but I couldn't figure out what I'm doing wrong.
The ultimate goal is that i define my two classes in a way so that a "Record" is linked to the "InstrumentInfo" table via the "UnifiedInstrumentCode" property.
My guess is that my constraints for this two tables are still not correct, but I cant figure out how to define it in EF6 (code first) to get this working.
Adding the annotation [DatabaseGenerated(DatabaseGeneratedOption.None)] to my primary key in InstrumentInfo solved the problem:
public class InstrumentInfo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int UnifiedInstrumentCode { get; set; }
public ICollection<Record> Record { get; set; }
public string AssetType { get; set; }
public int UnderlyingInstrumentUic { get; set; }
public string UnderlyingInstrumentSubType { get; set; }
public string InstrumentSymbol { get; set; }
public string InstrumentDescription { get; set; }
public string InstrumentSubType { get; set; }
public string UnderlyingInstrumentAssetType { get; set; }
public string UnderlyingInstrumentDescription { get; set; }
public string UnderlyingInstrumentSymbol { get; set; }
}
I did not investigate further but my guess is that if a new Record is added, EF initially creates and InstrumentInfo object that has a Null Value for its Primary key which causes the Exception.
I hope it helps if somebody runs into the same problem in future.

There are no primary in referenced table 'x' that match referencing column foreign key ".y"

There are no primary or candidate keys in the referenced table 'dbo.Client_Master' that match the referencing column list in the foreign key 'FK_dbo.Client_Question_Master_dbo.Client_Master_client_id'.
Could not create constraint or index. See previous errors.
My Client_Master Model
public class Client_Master
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Client_Id { get; set; }
public string Client_Name { get; set; }
public string Client_Address { get; set; }
public string Client_Email { get; set; }
public string Client_Phone { get; set; }
[DefaultValue(" ")]
public string Client_Country { get; set; }
[DefaultValue(" ")]
public string Client_State { get; set; }
[DefaultValue(" ")]
public string Client_Postcode { get; set; }
public bool Is_Active { get; set; }
public long? Created_By { get; set; }
public DateTime? Created_Date { get; set; }
[ForeignKey("Business_Master")]
public long? Business_Id { get; set; }
[ForeignKey("Categories")]
public long? Category_Id { get; set; }
public virtual Categories Categories { get; set; }
public virtual Business_Master Business_Master { get; set; }
[JsonIgnore]
public virtual ICollection<Client_Question_Master> Client_Question_Master { get; set; }
}
And My Client_Question_Master Modal
public class Client_Question_Master
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long client_question_master_id { get; set; }
[ForeignKey("Client_Master")]
public long? client_id { get; set; }
public virtual Client_Master Client_Master { get; set; }
[ForeignKey("Question_Types")]
public long? question_type_id { get; set; }
public virtual Question_Types Question_Types { get; set; }
public string question { get; set; }
public long order_no { get; set; }
public bool isContribute { get; set; } = true;
[ForeignKey("Section_Master")]
public long? section_id { get; set; }
public virtual Section_Master Section_Master { get; set; }
public double amount { get; set; }
public bool isActive { get; set; } = true;
public bool isRequired { get; set; } = true;
public bool isComment { get; set; } = true;
public string values { get; set; }
public bool isRevenue { get; set; }
public bool isStaff { get; set; }
public bool isMarketing { get; set; }
public DateTime created_date { get; set; } = DateTime.Now;
}
After add-migration during updating database it is giving me error.
Your usage of the ForeignKey attribute is the wrong way round, when using a nullable foreign key.
For example you use:
[ForeignKey("Client_Master")]
public long? client_id { get; set; }
public virtual Client_Master Client_Master { get; set; }
However it should be:
public long? client_id { get; set; }
[ForeignKey("client_id")]
public virtual Client_Master Client_Master { get; set; }
You tell EntityFramework what property is the foreign key. This prevent it from creating a field that has the same datatype as the primary key.
Check your edmx file.Edmx may not have that column as Primary key in another table which you are using as foreign key.

Code-First SQL Server ASP.NET MVC6

I am a VB.NET programmer, but I am trying to learn C# and MVC in my spare time. I am using ASP.NET MVC 5.1.0.0 and I am trying to do code-First database creation in a local instance of SQL Server.
I was able to get the first database table to update in the database when I ran Update-Database from within the IDE, but when I added a second table that has a PK/FK relationship with the first, I am getting a red line under [ForeignKey] which reads
Does not contain a constructor that takes 1 arguments
I have been searching all over and not getting anywhere. Any suggestions or help would be appreciated. By the way, the first table is a PK/FK relationship to the AspNetUsers table.
public class BuildDatabase : IdentityUser
{
public virtual Companies Companies { get; set; }
public virtual NotaryProfile NotaryProfile { get; set; }
}
public class Companies
{
[Key]
[Column("CompanyID")] // Did this as the database will reflect TableName_ColumnName instead.
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public bool IsActive { get; set; }
public bool IsNotary { get; set; }
public virtual ICollection<NotaryProfile> NotaryProfile { get; set; }
}
public class NotaryProfile
{
[Key]
public int NotaryID { get; set; }
public string NamePrefix { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public string NameSuffix { get; set; }
public bool IsActive { get; set; }
public int DefaultState { get; set; }
public int DefaultCounty { get; set; }
public bool IsSigningAgent { get; set; }
public bool HasABond { get; set; }
public decimal BondAmount { get; set; }
public bool HasEandO { get; set; }
public decimal EandOAmount { get; set; }
public bool ElectronicNotarizationsAllowed { get; set; }
public string ElectronicTechnologyUsed { get; set; }
public string ComissionNumber { get; set; }
public DateTime CommissionIssued { get; set; }
public DateTime CommssionOriginal { get; set; }
public DateTime CommissionExpires { get; set; }
public DateTime CommissionFiledOn { get; set; }
public string SOSAuditNumber { get; set; }
public string CommissionDesc { get; set; }
[Foreignkey("CompanyID")] // Companies.CompanyID = PK
public int CompanyID { get; set; } // PK/FK relationship.
public Companies Companies { get; set; } // Reference to Companies table above.
}
public class SchemaDBContext : IdentityDbContext<BuildDatabase>
{
public SchemaDBContext()
: base("DefaultConnection"){}
public DbSet<Companies> Companies { get; set; }
public DbSet<NotaryProfile> NotaryProfile { get; set; }
}
One of your classes (probably NotaryProfile) needs to reference another object (the foreign key relationship) but there is no constructor in that class that accepts an argument to establish that relationship, e.g.:
public NotaryProfile(int companyId) {
this.companyId = companyId;
}
BTW, a better way to establish that relationship is to use the actual class type rather than the ID, as in:
public class NotaryProfile {
...
public Company Company { get; set; }
// Instead of this:
// public int CompanyID { get; set; } // PK/FK relationship.
...
}
See also:
C# “does not contain a constructor that takes '1' arguments”
Does not contain a constructor that takes 2 arguments

Mapping complex DTOs to entities with automapper

I want to map from
LDTTicketUploadDTO[] to IEnumerable<LDTTicket>
The mappings are created in this method and at the end I map the data.
public void UploadLDTTickets(LDTTicketUploadDTO[] ticketDTOs)
{
Mapper.CreateMap<LDTTicketUploadDTO, LDTTicket>();
Mapper.CreateMap<LDTTicketDTO, LDTTicket>();
Mapper.CreateMap<LDTCustomerDTO, LDTCustomer>();
Mapper.CreateMap<LDTDeviceDTO, LDTDevice>();
Mapper.CreateMap<LDTUnitDTO, LDTUnit>();
Mapper.CreateMap<LDTCommandDTO, LDTCommand>();
Mapper.CreateMap<LDTCommandParameterDTO, LDTCommandParameter>();
Mapper.CreateMap<LDTObjectDTO, LDTObject>();
Mapper.CreateMap<LDTControlFileDTO, LDTControlFile>();
Mapper.CreateMap<LDTDeviceDTO, LDTDevice>();
Mapper.CreateMap<LDTLanguageDTO, LDTLanguage>();
Mapper.CreateMap<LDTObjectBitDTO, LDTObjectBit>();
var tickets = Mapper.Map<IEnumerable<LDTTicketUploadDTO>, IEnumerable<LDTTicket>>(ticketDTOs);
// do something with tickets
}
This is how the DTO´s are structured:
public class LDTTicketUploadDTO
{
public LDTTicketDTO Ticket { get; set; }
public LDTDeviceDTO Device { get; set; }
public LDTCustomerDTO Customer { get; set; }
}
public enum TicketStatus
{
New,
InProgress,
Done
}
public class LDTTicketDTO
{
public bool UploadNeeded { get; set; }
public string TicketNumber { get; set; }
public TicketStatus Status { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedOn { get; set; }
public string AssignedTo { get; set; }
public IEnumerable<LDTUnitDTO> Units { get; set; }
}
public class LDTUnitDTO
{
public int Id { get; set; }
public string FunctionUnit { get; set; }
public int FunctionUnitAddress { get; set; }
public string Zone { get; set; }
public int ZoneUnitAddress { get; set; }
public string Object { get; set; }
public int ObjectAddress { get; set; }
public IEnumerable<LDTCommandDTO> Commands { get; set; }
}
and more...
What works is that these properties are correctly mapped to their counterpart entities:
public LDTDeviceDTO Device { get; set; }
public LDTCustomerDTO Customer { get; set; }
What works NOT is that this property is not mapped:
public LDTTicketDTO Ticket { get; set; }
This is how the Entities are structured:
public class LDTTicket
{
[Key, Column(Order = 0)]
[Required]
public string SerialNumber { get; set; }
[Key, Column(Order = 1)]
[Required]
public string TicketNumber { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
public string AssignedTo { get; set; }
public TicketStatus Status { get; set; }
public string CreatedBy { get; set; }
public bool UploadNeeded { get; set; }
public virtual LDTCustomer Customer { get; set; }
public virtual LDTDevice Device { get; set; }
public virtual ICollection<LDTUnit> Units { get; set; }
}
ONLY the Customer and Device property are mapped in the LDTTicket
What is wrong with my configuration?
It's expecting to populate a LDTTicket sub-property on the ticket, not the matching properties of the ticket itself. Create direct mappings onto the ticket from the Ticket subproperty of the source directly onto the matching properties of the destination. NOTE: You only need to define your mappings once, not per method execution. Mappings should be defined at app start up and thereafter used.
public void UploadLDTTickets(LDTTicketUploadDTO[] ticketDTOs)
{
Mapper.CreateMap<LDTTicketUploadDTO, LDTTicket>();
.ForMember(d => d.SerialNumber, m => m.MapFrom(s => s.Ticket.SerialNumber))
...
//Mapper.CreateMap<LDTTicketDTO, LDTTicket>(); You don't need this
Mapper.CreateMap<LDTCustomerDTO, LDTCustomer>();
Mapper.CreateMap<LDTDeviceDTO, LDTDevice>();
...
}

How can I connect the fields of two tables in MVC 5?

I have two models and for which I will create tables through migration and database update. My first model is named Service, and it consists of these fields:
public class Service
{
public int ServiceID { get; set; }
public string ServiceType { get; set; }
public string Category { get; set; }
public string Subcategory { get; set; }
public int Count { get; set; }
}
My second model is called Business, and it has the following fields:
public class Business
{
public int BusinessID { get; set; }
public string BusinessName { get; set; }
public string BusinessWebsite { get; set; }
public string BusinessAddress { get; set; }
public string BusinessCity { get; set; }
public string BusinessState { get; set; }
public string BusinessZip { get; set; }
public string BusinessDescription { get; set; }
[Range(0.0, 5.0)]
public int Rating { get; set; }
public DateTime LastLogIn { get; set; }
// Need to add more fields
}
The point is that I want to add Category and Subcategory fields into my Business model, but the values of Category and Subcategory fields, should be one of the values inside the Service table's values for Category and Subcategory.
Simply, I want to connect those two fields. How can I achieve it? Should I just put a Service property inside the Business model?
Break out a separate entity for "Category" and then use foreign keys:
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class Service
{
...
public virtual Category Category { get; set; }
public virtual Category Subcategory { get; set; }
}
// Do the same when adding category/subcategory fields to `Business`
If you want to ensure that these categories are only tied to Service (and you potentially have other types of categories or something) you can always just make the entity ServiceCategory or something and only create a relationship to it from Service.
You need to separate your break out your database to store lookup table for category and a lookup table for subcategory.
Then you can create:
public class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
}
public class SubCategory {
public int SubCategoryId { get; set; }
public string Name { get; set; }
}
Then change your service class to:
public class Service
{
public int ServiceID { get; set; }
public string ServiceType { get; set; }
public int CategoryId { get; set; }
public int SubcategoryId { get; set; }
public int Count { get; set; }
}
and change your Business class to:
public class Business
{
public int BusinessID { get; set; }
public string BusinessName { get; set; }
public string BusinessWebsite { get; set; }
public string BusinessAddress { get; set; }
public string BusinessCity { get; set; }
public string BusinessState { get; set; }
public string BusinessZip { get; set; }
public string BusinessDescription { get; set; }
public int CategoryId { get; set; }
public int SubCategoryId { get; set; }
[Range(0.0, 5.0)]
public int Rating { get; set; }
public DateTime LastLogIn { get; set; }
// Need to add more fields
}

Categories