EF Code First is creating query with wrong columns - entity-framework

I am using EF 6.0 and creating my database views using code first. I have a small sample that works fine. I'm trying to migrate to another set of views. For some reason I am getting the wrong column name on the query for one of the columns. It seems to be bring in the column from the other view I'm joining to.
I've tried to change the [Key] columns on the tables but it just doesn't seem to change.
The view vABC consists of columns: name varchar(30) and desc varchar(100)
The view vXYZ consists of columns: name varchar(30) and amount float
They will join to each other on name.
This is a snippet of the query I am running:
var name = dataRecord.Cells[0].Value.ToString();
var query = from b in _context.XYZ
.Where(b => b.name == name)
select b;
This is returning:
SELECT
1 AS [C1],
[Extent1].[name] AS [name],
[Extent1].[amount] AS [amount],
[Extent1].[ABC_name] AS [ABC_name]
FROM [dbo].[vXYZ] AS [Extent1]
WHERE [Extent1].[name] = #p__linq__0
I will attached the classes and dbcontext below.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Mynamespace
{
[Table("vABC")]
public class ABC
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ABC()
{
XYZs= new HashSet<XYZ>();
}
[Key]
[StringLength(150)]
public string name { get; set; }
[StringLength(150)]
public string Desc { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<XYZ> XYZs{ get; set; }
}
}
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Mynamespace
{
[Table("vXYZ")]
public class Price
{
[Key]
[Required]
[StringLength(200)]
public string name{ get; set; }
public decimal? amount{ get; set; }
public virtual ABC ABC{ get; set; }
}
}
namespace Mynamespace
{
using System.Data.Entity;
public partial class myContext : DbContext
{
public myContext () : base("name=myContext ")
{
Database.SetInitializer<myContext >(null);
}
public virtual DbSet<ABC> ABCs { get; set; }
public virtual DbSet<XYZ> XYZs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<XYZ>()
.Property(e => e.amount)
.HasPrecision(19, 4);
}
}
}
I am expecting query to be
SELECT [Extent1].[name] AS [name],
[Extent1].[amount] AS [amount]
FROM [dbo].[vXYZ] AS [Extent1]
WHERE [Extent1].[name] = #p__linq__0

Related

Accessing objects via DbContext with PowerShell

I'd like to access objects from my Entity Framework Core based database via PowerShell.
I can load the DLL which contains the DbContext and instantiate an instance of it. However, when accessing a property to get to the elements in the database, I get the following error:
The text in that screenshot follows:
PS C:\temp\RedditDhtk\RedditDhtk\bin\Debug> Add-Type -Path .\RedditDhtk.dll
PS C:\temp\RedditDhtk\RedditDhtk\bin\Debug> $db = [RedditDhtkDb.RedditContext]::new()
PS C:\temp\RedditDhtk\RedditDhtk\bin\Debug> $db.Links
The following exception occurred while trying to enumerate the collection: "Could not load file or assembly
'System.ComponentModel.Annotations, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its
dependencies. The system cannot find the file specified.".
At line:1 char:1
+ $db.Links
+ ~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
+ FullyQualifiedErrorId : ExceptionInGetEnumerator
I've tried to load the assembly mentioned in the error, System.ComponentModel.Annotations with Add-Path, but that didn't seem to help.
The C# code for that file which implements the DbContext subclass is shown below in case that's helpful.
Any suggestions welcome!
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RedditDhtkDb
{
public class Link
{
[Key]
public string Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public string Permalink { get; set; }
public DateTime CreatedUtc { get; set; }
public string Name { get; set; }
public int Score { get; set; }
public string Subreddit { get; set; }
public string Author { get; set; }
public int NumComments { get; set; }
public string SelfText { get; set; }
// non-reddit column
public DateTime LastUpdated { get; set; }
public DateTime CommentsLastUpdated { get; set; }
}
public class Comment
{
[Key]
public string Id { get; set; }
public string LinkId { get; set; }
public string ParentId { get; set; }
public string Name { get; set; }
public DateTime CreatedUtc { get; set; }
public bool Edited { get; set; }
public string Author { get; set; }
public int Score { get; set; }
public string Body { get; set; }
// non-reddit column
public DateTime LastUpdated { get; set; }
}
[NotMapped]
public class SpaceUsed
{
public string TableName { get; set; }
public decimal TotalSpaceMB { get; set; }
public static List<SpaceUsed> GetSpaceUsed(RedditContext db)
{
return db.SpaceUsed.FromSql(#"SELECT t.NAME AS TableName,
CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS TotalSpaceMB
FROM sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
t.NAME NOT LIKE 'dt%'
AND t.is_ms_shipped = 0
AND i.OBJECT_ID > 255
GROUP BY
t.Name, s.Name, p.Rows
ORDER BY
t.Name").ToList();
}
}
public class RedditContext : DbContext
{
public DbSet<Link> Links { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbQuery<SpaceUsed> SpaceUsed { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=LAPTOP-G10E2AOC\SQL2016;Database=reddit-dhtk-cs-ef-core;Integrated Security=True");
}
}
}
You can try loading your dlls using "[System.Reflection.Assembly]::LoadWithPartialName()"
You can also try by providing the full path for dlls.
Thanks

Why navigation property is always returning null even if the data exists?

I'm badly stuck on this one, I've a one to many relationship between two models (POS_cities,POS_company)
POS_cities.cs
public class POS_cities
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int CountryID { get; set; }
public virtual POS_country country { get; set; }
public virtual ICollection<POS_company> company { get; set; }
}
POS_company.cs
public class POS_company
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string BusinessName { get; set; }
public int CityID { get; set; }
public virtual POS_cities cities { get; set; }
}
So, I scaffold the above using Entity framework, but it did not generate the code as expected, so, I had to modify the code according to my need, such as the below Index action :
public ActionResult Index()
{
var pOS_company = db.POS_company.Include(p => p.cities);
return View(pOS_company.ToList());
}
In the above code EF did not generate the Include(p => p.cities) function, so, I had to add that explicitly. Now, when I execute the above Index() action, the navigation property cities returns null even if the data is present in database :
Now, let's make sure that data is actually present in database :
Data in POS_cities
Data in POS_company
So, what could possibly be the thing I'm doing wrong? Why the navigation property cities is returning null even if the data is present in database? Thanks in Advance :)
Update
"SELECT [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[BusinessName] AS [BusinessName], [Extent1].[CityID] AS [CityID], [Extent2].[ID] AS [ID1], [Extent2].[Name] AS [Name1], [Extent2].[CountryID] AS [CountryID] FROM [dbo].[POS_company] AS [Extent1] LEFT OUTER JOIN [dbo].[POS_cities] AS [Extent2] ON [Extent1].[CityID1] = [Extent2].[ID]"
Try this:
public class POS_company
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string BusinessName { get; set; }
[ForeignKey("CityID")]
public virtual POS_cities cities { get; set; }
public int CityID { get; set; }
}

Entity Framework many to many table insert complex relations

This is my simplified schema.
I want to add a contact who is a custodian and attach them to an existing facility. The ContactType just states what type of contact the record is such as a company or individual. In this case the custodian is an individual.
I can insert a contact by itself just fine.
The complication for me is because of the many to many and one to many relationships.
In the controller I have
vm.Contact.Facilities.Add(new Facility { FacilityID = vm.SelectedFacilityID });
_repo.SaveContact(vm);
In the repo
_db.Contacts.Add(vm.Contact);
_db.SaveChanges();
This gives me a foreign key error since it tries to insert a new facility and I have other foreign keys in that table not shown. I don't want to add a facility but just reference the FacilityID.
Convention is to Not explicitly try to insert a record in the many to many, FacilityCustodian table directly by doing something like this
var fc = new FacilityCustodian { CustodianFacilityID = vm.SelectedFacilityID };
vm.Contact.FacilityCustodian.Add(fc);
I also tried
foreach (var facility in vm.Contact.Facilities)
{
_db.Entry(facility).State = EntityState.Unchanged;
}
Most of the examples I have seen don't have both relationships so I'm not sure how to proceed.
Thanks for any help.
ADDED CODE
using Licensing.Models;
namespace Licensing
{
using System.Data.Entity;
public class Context : DbContext
{
public Context()
: base("name=Context")
{
}
public virtual DbSet<Contact> Contacts { get; set; }
public virtual DbSet<ContactType> ContactTypes { get; set; }
public virtual DbSet<Facility> Facilities { get; set; }
public virtual DbSet<FacilityCandler> FacilityCustodians { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>()
.Property(e => e.FName)
.IsUnicode(false);
modelBuilder.Entity<Contact>()
.Property(e => e.LName)
.IsUnicode(false);
modelBuilder.Entity<Contact>()
.HasMany(e => e.Facilities)
.WithRequired(e => e.Contact)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Contact>()
.HasMany(e => e.FacilityCustodians)
.WithRequired(e => e.Contact)
.HasForeignKey(e => e.CustodianFacilityID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<ContactType>()
.Property(e => e.Type)
.IsUnicode(false);
modelBuilder.Entity<ContactType>()
.HasMany(e => e.Contacts)
.WithRequired(e => e.ContactType)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Facility>()
.HasMany(e => e.FacilityCustodians)
.WithRequired(e => e.Facility)
.HasForeignKey(e => e.CustodianFacilityID)
.WillCascadeOnDelete(false);
}
}
}
namespace Licensing.Models
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("Contact")]
public class Contact
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Contact()
{
Facilities = new HashSet<Facility>();
FacilityCustodians = new HashSet<FacilityCustodian>();
}
[Key]
public int ContactID { get; set; }
public int ContactTypeID { get; set; }
[Display(Name = "First Name")]
[RegularExpression(#"^[a-zA-Z'.\s]+$", ErrorMessage = "Enter a valid Name")]
[StringLength(150)]
public string FName { get; set; }
[Display(Name = "Last Name")]
[RegularExpression(#"^[a-zA-Z'\s]+$", ErrorMessage = "Enter a valid Name")]
[StringLength(150)]
public string LName { get; set; }
public virtual ContactType ContactType { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Facility> Facilities { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<FacilityCustodian> FacilityCustodians { get; set; }
}
}
using System.ComponentModel.DataAnnotations;
namespace Licensing.Models
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
[Table("Facility")]
public class Facility
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Facility()
{
FacilityCustodians = new HashSet<FacilityCustodian>();
}
[Key]
public int FacilityID { get; set; }
public int ContactID { get; set; }
public virtual Contact Contact { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<FacilityCustodian> FacilityCustodians { get; set; }
}
}
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Licensing.Models
{
[Table("FacilityCustodian")]
public partial class FacilityCustodian
{
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CustodianFacilityID { get; set; }
[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CustodianContactID { get; set; }
public virtual Contact Contact { get; set; }
public virtual Facility Facility { get; set; }
}
}
namespace Licensing.Models
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("ContactType")]
public class ContactType
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ContactType()
{
Contacts = new HashSet<Contact>();
}
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ContactTypeID { get; set; }
[Required]
[StringLength(10)]
public string Type { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Contact> Contacts { get; set; }
}
}
UPDATE Working Code
var existingFacility = _repo.GetFacilityByFacilityID(vm.SelectedFacilityID);
vm.Contact.LName = vm.LName;
vm.Contact.FName = vm.FName;
vm.Contact.Name = vm.FName + " " + vm.LName;
vm.Contact.ContactTypeID = 1;
vm.Contact.FacilityCustodians.Add(existingFacility);
_db.Contacts.Add(vm.Contact);
_db.SaveChanges();
Try this Since I dont have complete folder I tried to simplify the model all classes are name mentioned in diagram but I create. Below are my model classes . The import thing to note is that read the entoty from contecxt first and then updated the values and set entitystate accordingly . This will solve your issue .
Model classes :-
public class ContactType
{
public int ContactTypeId { get; set; }
public string Name { get; set; }
}
public class Contact
{
public int ContactId { get; set; }
public string Name { get; set; }
public int ContactTypeId { get; set; }
[ForeignKey("ContactTypeId")]
public virtual ContactType ContactType { get; set; }
public virtual ICollection<Facility> Facilities { get; set; }
}
public class FacilityCustodian
{
public int FacilityId { get; set; }
public int ContactTypeId { get; set; }
[ForeignKey("ContactId")]
public virtual Contact Contact { get; set; }
[ForeignKey("FacilityId")]
public virtual
Facility Facility { get; set; }
}
public class Facility
{
public int FacilityId { get; set; }
public string Location { get; set; }
public int ContactId { get; set; }
[ForeignKey("ContactId")]
public virtual Contact Contact { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
-- here I am showing you to update existing contact and add a new facility to it . same as you case you want to update facility ...
using (var ctx = new SampleDbContext())
{
//this is important to read the entity first .
var contact = ctx.Contacts.FirstOrDefault(x=>x.ContactId ==vm.Contact.ContactId);
if (contact != null)
{
// Since facilityId is a primary key I set it to autoincrement so I dont have to set it .You can set if it is not primarykey
contact.Name = "Updated";
// update the entity and add new information inthis i am adding facility
var facility = new Facility
{
Location = "LocA",
// assiging same entity to facility so that it will not treat it as a new contact
Contact = contact
};
contact.Facilities.Add(facility);
// Finaly update the state of the entity .
ctx.Entry(contact).State = EntityState.Modified;
ctx.SaveChanges();
}
}
After this it will not insert new contact when you save in . In my example I choose to add new facility but keep contact same . You can do same with facility but the concept is same . First read the object from EF coontext update values which you need to update and set state to Modified . This will tell that all other Entities in graph are same expect which you modified.
SQL Profiler Query to make sure Update happn for Contact and insert for facility
exec sp_executesql N'UPDATE [dbo].[Contacts]
SET [Name] = #0, [ContactTypeId] = #1
WHERE ([ContactId] = #2)
',N'#0 nvarchar(max) ,#1 int,#2 int',#0=N'Updated',#1=1,#2=1
go
exec sp_executesql N'INSERT [dbo].[Facilities]([Location], [ContactId], [Contact_ContactId])
VALUES (#0, #1, #2)
SELECT [FacilityId]
FROM [dbo].[Facilities]
WHERE ##ROWCOUNT > 0 AND [FacilityId] = scope_identity()',N'#0nvarchar(max) ,#1 int,#2 int',#0=N'LocA',#1=1,#2=1
go

Code First conventions for foreign keys and table names

Please accept my apologies for the large amount of text, I tried not to miss the details that may affect on something
Entity Framework 4.3.1
My Model:
public class Podcast
{
public int Id { get; set; }
public string Title { get; set; }
public int PodcastStatus_Id { get; set; }
public int PodcastType_Id { get; set; }
public virtual PodcastStatus PodcastStatus { get; set; }
public virtual PodcastType PodcastType { get; set; }
public virtual ICollection<CategoryLink> CategoryLinks { get; set; }
}
public class PodcastStatus
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Podcast> Podcasts { get; set; }
}
public class PodcastType
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Podcast> Podcasts { get; set; }
}
Context:
public class EcDbContext : DbContext
{
public DbSet<PodcastType> PodcastTypes { get; set; }
public DbSet<PodcastStatus> PodcastStatuses { get; set; }
public DbSet<Podcast> Podcasts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Podcast>().HasRequired(p => p.PodcastStatus).WithMany(s => s.Podcasts).HasForeignKey(p => p.PodcastStatus_Id);
modelBuilder.Entity<Podcast>().HasRequired(p => p.PodcastType).WithMany(t => t.Podcasts).HasForeignKey(p => p.PodcastType_Id);
base.OnModelCreating(modelBuilder);
}
}
Query:
db.Podcasts.Where(p => p.PodcastStatus.SysStatus > 0 && p.Title.Contains(search))
.OrderBy(p => p.CreatedDate)
.Skip((page - 1) * PageSize).Take(PageSize)
Here I've deleted some columns from the Model descriptions so to not complicate things.
I get the following error message: Invalid object name 'dbo.PodcastStatus'. This table is named 'PodcastStatuses' in the database. We will see the following text if we look at the result SQL query:
{SELECT TOP (10)
[Project1].[Id] AS [Id],
[Project1].[Title] AS [Title],
[Project1].[CreatedDate] AS [CreatedDate],
[Project1].[PodcastStatus_Id] AS [PodcastStatus_Id],
[Project1].[PodcastType_Id] AS [PodcastType_Id],
[Project1].[PodcastStatus_Id1] AS [PodcastStatus_Id1],
[Project1].[PodcastType_Id1] AS [PodcastType_Id1]
FROM ( SELECT [Project1].[Id] AS [Id], [Project1].[CastNo] AS [CastNo], [Project1].[Title] AS [Title], [Project1].[OriginalText] AS [OriginalText], [Project1].[TranslateText] AS [TranslateText], [Project1].[CreatedDate] AS [CreatedDate], [Project1].[PodcastStatus_Id] AS [PodcastStatus_Id], [Project1].[PodcastType_Id] AS [PodcastType_Id], [Project1].[ImageFileName] AS [ImageFileName], [Project1].[PodcastStatus_Id1] AS [PodcastStatus_Id1], [Project1].[PodcastType_Id1] AS [PodcastType_Id1], row_number() OVER (ORDER BY [Project1].[CreatedDate] ASC) AS [row_number]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title],
[Extent1].[CreatedDate] AS [CreatedDate],
[Extent1].[PodcastStatus_Id] AS [PodcastStatus_Id],
[Extent1].[PodcastType_Id] AS [PodcastType_Id],
[Extent1].[PodcastStatus_Id1] AS [PodcastStatus_Id1],
[Extent1].[PodcastType_Id1] AS [PodcastType_Id1]
FROM [dbo].[Podcasts] AS [Extent1]
INNER JOIN [dbo].[PodcastStatus] AS [Extent2] ON [Extent1].[PodcastStatus_Id] = [Extent2].[Id]
WHERE ([Extent2].[SysStatus] > 0) AND ((N'' = #p__linq__0) OR ([Extent1].[Title] LIKE #p__linq__1 ESCAPE N'~'))
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[CreatedDate] ASC}
PodcastStatus_Id1, PodcastStatus_Id1, [dbo].[PodcastStatus] (and not 'statusES'), [PodcastStatus_Id] = [Extent2].[Id]
Why? I don't understand what did I do wrong...
Can somebody help?
Thanks!
It looks like a problem when EF pluralizes names when generating the database - I ran across something like this a while ago but I forget which EF version.
You can force EF to name a table by using (although you will likely need to drop/recreate the database) :
[Table("PodcastStatus")]
public class PodcastStatus
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Podcast> Podcasts { get; set; }
}

Linking two tables in EntityFramework CodeFirst models

I am trying to learn asp.net MVC, by converting a web forms app I have. It's a room booking app, where there is a customer table (tblCustomerBooking) which has a one to many relationship with tblRental - so one customer can book more than one room. The fields that match each other are tblCustomerBooking.customer_id -> tblRental.customer_ref
I'm trying to use code first - and building a model class - but I can't figure out how to link the two tables, so that when I query the dbContext, it will return a customer, with one or more rentals within the same model.
My table definitions are:
CREATE TABLE [dbo].[tblCustomerBooking](
[customer_id] [bigint] IDENTITY(1,1) NOT NULL,
[room_id] [bigint] NULL,
[customer_name] [varchar](110) NULL,
[customer_email] [varchar](50) NULL
CONSTRAINT [PK_tblCustomerBooking] PRIMARY KEY CLUSTERED
(
[customer_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
CREATE TABLE [dbo].[tblRental](
[rental_id] [bigint] IDENTITY(1,1) NOT NULL,
[room_id] [bigint] NOT NULL,
[check_in] [datetime] NOT NULL,
[check_out] [datetime] NOT NULL,
[customer_ref] [bigint] NULL,
[room_cost] [decimal](18, 2) NULL
CONSTRAINT [PK_tblRental_1] PRIMARY KEY CLUSTERED
([rental_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
My attempt at building the model for this is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity;
namespace MvcApplication23.Models
{
public class tblRental
{
[Key()]
public int rental_id { get; set; }
public int room_id { get; set; }
public DateTime check_in { get; set; }
public DateTime check_out { get; set; }
public long customer_ref { get; set; }
[ForeignKey("customer_ref")]
public tblCustomerBooking Customer {get;set;}
public decimal room_cost { get; set; }
}
public class tblCustomerBooking
{
[Key()]
public long customer_id { get; set; }
public string customer_name { get; set; }
public string customer_email { get; set; }
public ICollection<tblRental> Rentals {get;set;}
}
public class RentalContext : DbContext
{
public DbSet<tblCustomerBooking> customers { get; set; }
public DbSet<tblRental> rentals { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using MvcApplication23.Models;
namespace MvcApplication23.api.Controllers
{
public class RentalController : ApiController
{
private RentalContext db = new RentalContext();
// GET /api/rental/5
public IQueryable<tblCustomerBooking> Get(int id)
{
return db.customers.Include("rentals").FirstOrDefault(c=>c.customer_id==id);
}
** I've updated the info above, with the actual table names that already existed in the database **
How to I link the two tables in the model? And then given a customer_id, how would I query the DbContext to return a customer, with any related entries in the tblRental table?
Thank you very much for any pointers,
Mark
To link two entities, provide a navigation property:
public class Rental
{
[Key]
public int rental_id { get; set; }
public int room_id { get; set; }
public DateTime check_in { get; set; }
public DateTime check_out { get; set; }
public int customer_ref { get; set; }
[ForeignKey("customer_ref")]
public virtual Customer Customer {get;set;}
public decimal room_cost { get; set; }
}
public class Customer
{
[Key]
public int customer_id { get; set; }
public string customer_name { get; set; }
public string customer_email { get; set; }
public virtual ICollection<Rental> Rentals {get;set;}
}
And to query your customer :
return this.DataContext.customers.Include("Rentals").FirstOrDefaul(c=>c.customer_id==customerId);
using System.ComponentModel.DataAnnotations.Schema;
public class Rental
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int id { get; set; }
public virtual int room_id { get; set; }
public virtual DateTime check_in { get; set; }
public virtual DateTime check_out { get; set; }
public virtual int customer_id { get; set; }
public virtual decimal room_cost { get; set; }
#region Navigation Properties
[ForeignKey("customer_id")]
public virtual Customer Customer { get; set; }
#endregion
}
public class Customer
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
public virtual ICollection<Rental> Rentals {get;set;}
}