Code First conventions for foreign keys and table names - entity-framework

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; }
}

Related

How to write this SQL statement using count and join in Entity Framework 6

I want to display the results of this SQL query in a WPF datagrid. My question how to run this query using EF6?
select c.*, count(o.id) from clients c
left join optics o
on o.client_id = c.id
where o.r_sph = 12 // 12 is a variable value
group by c.id
My Clients model:
public clients()
{
this.optics = new ObservableCollection<optics>();
}
public long id { get; set; }
public string name { get; set; }
public string phone { get; set; }
public Nullable<System.DateTime> date_of_birth { get; set; }
public System.DateTime inserted_at { get; set; }
public System.DateTime updated_at { get; set; }
public virtual ObservableCollection<optics> optics { get; set; }
And Optics model:
public long id { get; set; }
public Nullable<System.DateTime> at { get; set; }
public Nullable<decimal> r_sph { get; set; }
public Nullable<int> r_axs { get; set; }
public string notes { get; set; }
public Nullable<long> client_id { get; set; }
public System.DateTime inserted_at { get; set; }
public System.DateTime updated_at { get; set; }
public virtual clients clients { get; set; }
Update:
I use this code to filter the results:
public IQueryable < Multi.Model.clients > FilterClients(optisysEntities db, System.Linq.IQueryable < Multi.Model.clients > clients, ClientsFilter clientsFilter) {
if (!String.IsNullOrWhiteSpace(clientsFilter.Name))
clients = db.clients.Where(c => c.name.Contains(clientsFilter.Name));
if (!String.IsNullOrWhiteSpace(clientsFilter.Phone))
clients = clients.Where(u => u.phone.Contains(clientsFilter.Phone));
}
You will need to return a new object (unless you already have a model set up which includes the "Count" property). Something like this:
var query = (from c in context.Clients
join o in context.Optics
on c.id equals o.client_id
where o.r_sph == 12
group new { c, o } by new { c.Id }
into g
select new {Id = g.Key.id,
// other properties from "Client",
Count = g.Count()}
).ToList();

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 6 - Configuration mapping from multiple tables

I have two tables which looks like below:
http://s30.postimg.org/i3u7pmpz5/baza.png
I created models looks like below:
public class DomainUser : User
{
public Guid Guid { get; set; }
public string Sid { get; set; }
public string Title { get; set; }
public string Company { get; set; }
public string Department { get; set; }
public string Office { get; set; }
public virtual DomainPhone Phone { get; set; }
public virtual DomainEmail Email { get; set; }
public string Created { get; set; }
public string CreatedBy { get; set; }
public string Modified { get; set; }
public string ModifiedBy { get; set; }
}
public abstract class User
{
public int Id { get; set; }
public string Login { get; set; }
public string Name { get; set; }
public string MiddleName { get; set; }
public string Surname { get; set; }
public bool IsActive { get; set; }
}
I want to create DomainUser object with data from table DomainUser and User.
Here is a sample query which we want to generate by EF:
select [Extent1].[Id] as [Id],
[Extent1].[Login] as [Login],
[Extent2].[Guid] as [Guid],
[Extent2].[Sid] as [Sid],
[Extent2].[Title] as [Title],
[Extent2].[Company] as [Company],
[Extent2].[Department] as [Department],
[Extent2].[Office] as [Office]
from [dbo].[User] as [Extent1] inner join [dbo].[DomainUser] as [Extent2] on [Extent1].[Id] = [Extent2].[Id]
How I can achieve this?

EntityFramework 4 returning all columns when I just want one back

I can't figure out why entityframework is returning me all columns on the below two queries. I'm trying to get it to return me just the date column but back all the columns of db.EmailDetails come when I look at the sql generated (posted below)
var y = (from data1 in db.EmailDetails
join data2 in db.AddressBookEntries on data1.FromAddressBookEntryId equals data2.Id
orderby data1.EmailSendFinishTime descending
select data1.EmailSendFinishTime).FirstOrDefault();
var x =
db.EmailDetails.Where(a => a.User.Username == username && a.FromAddressBookEntry.WhiteList).
Select(a => new
{
a.EmailSendFinishTime
}).
OrderByDescending(
a => a.EmailSendFinishTime)
.FirstOrDefault();
sql generated:
exec sp_executesql N'SELECT TOP (1)
[Project1].[Id] AS [Id],
[Project1].[UserId] AS [UserId],
[Project1].[InValidMailMessage] AS [InValidMailMessage],
[Project1].[MailInternalDate] AS [MailInternalDate],
[Project1].[MessageUniqueId] AS [MessageUniqueId],
[Project1].[FromAddressBookEntryId] AS [FromAddressBookEntryId],
[Project1].[ToEmailAddress] AS [ToEmailAddress],
[Project1].[EmailFolderId] AS [EmailFolderId],
[Project1].[EmailHeaderInfo] AS [EmailHeaderInfo],
[Project1].[EmailSendSmtpServer] AS [EmailSendSmtpServer],
[Project1].[EmailSendStatus] AS [EmailSendStatus],
[Project1].[EmailSendStartTime] AS [EmailSendStartTime],
[Project1].[EmailSendFinishTime] AS [EmailSendFinishTime],
[Project1].[EmailSendLogMessage] AS [EmailSendLogMessage],
[Project1].[Subject] AS [Subject],
[Project1].[MimeMessageFull] AS [MimeMessageFull],
[Project1].[HighPriority] AS [HighPriority],
[Project1].[SentDateTime] AS [SentDateTime],
[Project1].[EmailDeleted] AS [EmailDeleted],
[Project1].[EmailDeletedDateTime] AS [EmailDeletedDateTime],
[Project1].[EmailViewed] AS [EmailViewed],
[Project1].[EmailViewedDateTime] AS [EmailViewedDateTime],
[Project1].[BodyTextForSend] AS [BodyTextForSend],
[Project1].[ReceivedDate] AS [ReceivedDate]
FROM ( SELECT [Extent1].[Id] AS [Id],
[Extent1].[UserId] AS [UserId],
[Extent1].[InValidMailMessage] AS [InValidMailMessage],
[Extent1].[MailInternalDate] AS [MailInternalDate],
[Extent1].[MessageUniqueId] AS [MessageUniqueId],
[Extent1].[FromAddressBookEntryId] AS [FromAddressBookEntryId],
[Extent1].[ToEmailAddress] AS [ToEmailAddress],
[Extent1].[EmailFolderId] AS [EmailFolderId],
[Extent1].[EmailHeaderInfo] AS [EmailHeaderInfo],
[Extent1].[EmailSendSmtpServer] AS [EmailSendSmtpServer],
[Extent1].[EmailSendStatus] AS [EmailSendStatus],
[Extent1].[EmailSendStartTime] AS [EmailSendStartTime],
[Extent1].[EmailSendFinishTime] AS [EmailSendFinishTime],
[Extent1].[EmailSendLogMessage] AS [EmailSendLogMessage],
[Extent1].[Subject] AS [Subject],
[Extent1].[MimeMessageFull] AS [MimeMessageFull],
[Extent1].[HighPriority] AS [HighPriority],
[Extent1].[SentDateTime] AS [SentDateTime],
[Extent1].[EmailDeleted] AS [EmailDeleted],
[Extent1].[EmailDeletedDateTime] AS [EmailDeletedDateTime],
[Extent1].[EmailViewed] AS [EmailViewed],
[Extent1].[EmailViewedDateTime] AS [EmailViewedDateTime],
[Extent1].[BodyTextForSend] AS [BodyTextForSend],
[Extent1].[ReceivedDate] AS [ReceivedDate]
FROM [dbo].[EmailDetails] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] =
[Extent2].[Id]
INNER JOIN [dbo].[AddressBookEntries] AS [Extent3] ON
[Extent1].[FromAddressBookEntryId] = [Extent3].[Id]
WHERE ([Extent2].[Username] = #p__linq__0) AND
([Extent3].[WhiteList] = 1)) AS [Project1]
ORDER BY [Project1].[EmailSendFinishTime] DESC',N'#p__linq__0 nvarchar(4000)
',#p__linq__0=N'ekellner9
EmailDetail Definition and AddressBookEntry Definition
public class EmailDetail
{
public EmailDetail()
{
// keep sqlserver from blowing up with no datetime set
EmailSendStartTime = new DateTime(1900, 1, 1);
EmailSendFinishTime = new DateTime(1900, 1, 1);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required(ErrorMessage = "Must have user associted with EmailDetail")]
public User User { get; set; }
public long? FromAddressBookEntryId { get; set; }
public AddressBookEntry FromAddressBookEntry { get; set; }
public DateTime EmailSendStartTime { get; set; }
public DateTime EmailSendFinishTime { get; set; }
}
public class AddressBookEntry
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required]
public User User { get; set; }
[MaxLength(512)]
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
}
I'm not getting the same results as you. Using the following console app:
public class EmailDetail
{
public EmailDetail()
{
// keep sqlserver from blowing up with no datetime set
EmailSendStartTime = new DateTime(1900, 1, 1);
EmailSendFinishTime = new DateTime(1900, 1, 1);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required(ErrorMessage = "Must have user associted with EmailDetail")]
public User User { get; set; }
public long? FromAddressBookEntryId { get; set; }
public AddressBookEntry FromAddressBookEntry { get; set; }
public DateTime EmailSendStartTime { get; set; }
public DateTime EmailSendFinishTime { get; set; }
}
public class AddressBookEntry
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[ForeignKey("User")]
public long UserId { get; set; }
[Required]
public User User { get; set; }
[MaxLength(512)]
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
public bool WhiteList { get; set; }
}
public class User
{
public long UserId { get; set; }
public string Username { get; set; }
}
public class CFContext : DbContext
{
public DbSet<AddressBookEntry> AddressBookEntries { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<EmailDetail> EmailDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
class Program
{
static void Main(string[] args)
{
var db = new CFContext();
var y = (from data1 in db.EmailDetails
join data2 in db.AddressBookEntries on data1.FromAddressBookEntryId equals data2.Id
orderby data1.EmailSendFinishTime descending
select data1.EmailSendFinishTime).FirstOrDefault();
string username = "1";
var x = db.EmailDetails.Where(a => a.User.Username == username && a.FromAddressBookEntry.WhiteList).
Select(a => new
{
a.EmailSendFinishTime
}).
OrderByDescending(
a => a.EmailSendFinishTime)
.FirstOrDefault();
Console.WriteLine(y);
Console.WriteLine(x);
}
}
I got these SQL queries
SELECT TOP (1)
[Extent1].[EmailSendFinishTime] AS [EmailSendFinishTime]
FROM [dbo].[EmailDetails] AS [Extent1]
WHERE [Extent1].[FromAddressBookEntryId] IS NOT NULL
ORDER BY [Extent1].[EmailSendFinishTime] DESC
SELECT TOP (1)
[Project1].[C1] AS [C1],
[Project1].[EmailSendFinishTime] AS [EmailSendFinishTime]
FROM ( SELECT
[Extent1].[EmailSendFinishTime] AS [EmailSendFinishTime],
1 AS [C1]
FROM [dbo].[EmailDetails] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[UserId]
INNER JOIN [dbo].[AddressBookEntries] AS [Extent3] ON [Extent1].[FromAddressBookEntryId] = [Extent3].[Id]
WHERE ([Extent2].[Username] = #p__linq__0) AND ([Extent3].[WhiteList] = 1)
) AS [Project1]
ORDER BY [Project1].[EmailSendFinishTime] DESC
Is there anything else in your model, or maybe there's something else making the SQL query above?

EF 4.1 code first still looking for old table that no longer exists

I am using Entity Framework 4.1 code first.
I had a table in the database with the name MaritalStatus. I deleted it and created a new table in its place called MaritalStatuses. Whenever I try to get all the records from the table I get an error:
Invalid object name 'dbo.MaritalStatus'.
The query that it is trying to execute is:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[IsActive] AS [IsActive]
FROM [dbo].[MaritalStatus] AS [Extent1]}
Why would it still be looking for table MaritalStatus that I deleted? Can it be possible that it is cached somewhere? I dropped the whole database and recreated it via scripts. Still no luck. Maybe it has an issue when it comes to the "es" part of the name?
Context class:
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
}
View model (with partial properties):
public class EditGrantApplicationViewModel
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int MaritalStatusId { get; set; }
public IEnumerable<MaritalStatus> MaritalStatuses { get; set; }
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
public int AccountTypeId { get; set; }
public IEnumerable<AccountType> AccountTypes { get; set; }
}
Dropdown list in view for MaritalStatuses:
<td><label>Marital Status:</label> <span class="red">**</span></td>
<td>
#Html.DropDownListFor(x => x.MaritalStatusId, new SelectList(Model.MaritalStatuses, "Id", "Name", Model.MaritalStatusId), "-- Select --")
#Html.ValidationMessageFor(x => x.MaritalStatusId)
</td>
Controller:
public ActionResult Create()
{
EditGrantApplicationViewModel viewModel = new EditGrantApplicationViewModel
{
MaritalStatuses = maritalStatusService.GetAll(),
Banks = bankService.GetAll(),
AccountTypes = accountTypeService.GetAll()
};
return View(viewModel);
}
Service:
public IEnumerable<MaritalStatus> GetAll()
{
return maritalStatusRepository.GetAll();
}
Repository:
HefContext db = new HefContext();
public IEnumerable<MaritalStatus> GetAll()
{
return db.MaritalStatuses;
}
Model class:
public class MaritalStatus
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
You may have renamed the table in your database, but your Model class is still tied to the old name. You need to map the entity to the desired table name in the OnModelCreating method of your DbContext object
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MaritalStatus>().ToTable("MaritalStatuses");
}
}
Update:
Apparently EF code first has some issues with the pluralization of some table names, such as Status. Out of curiosity I tested a few others and found several which also had this same issue.
I guess this is wrong:
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
Should be:
public DbSet<MaritalStatuses> MaritalStatuses { get; set; }