I'm getting the following error when I try to insert a new row in one of my relational tables. I have the following two models:
public class CompanyCredit
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int creditId { get; set; }
public int planCredit { get; set; }
public DateTime? PlanCreditExpirationDate { get; set; }
}
And
public class CompanyInformation
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Required]
[DisplayName("Company Name:")]
public string companyName { get; set; }
public string timeZone { get; set; }
//navigation Properties
public virtual CompanyCredit Credits { get; set; }
}
And this Relation in the dbContext
modelBuilder.Entity<CompanyInformation>().HasOptional(e => e.Credits);
I'm trying to add a record inside CompanyCredit table like so:
if (_company.Credits == null)
{
var _credits = new CompanyCredit();
_credits.planCredit = 200;
_credits.PlanCreditExpirationDate = System.DateTime.UtcNow.AddMonths(1);
_company.Credits = _credits;
repo.InsertOrUpdate(_company, User.Identity.Name);
}
And Finally Insert or update just marks Company as changed and _credit as added like so:
_db.Entry(_credits).State = System.Data.EntityState.Added;
_db.Entry(Company).State = System.Data.EntityState.Modified;
_db.SaveChanges();
When this runs I get the following Error that I just can't seem to find the reason to.
Cannot insert the value NULL into column 'creditId', table 'Project.dbo.CompanyCredits'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Thank in advanced for your help.
I found the problem was in the attribute [DatabaseGenerated(DatabaseGeneratedOption.Identity)] this should have been [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
I thought I would post this so others might benefit from it.
Could you please try reversing the order of entity state modification, just before the saveChanges call
_db.Entry(Company).State = System.Data.EntityState.Modified;
_db.Entry(_credits).State = System.Data.EntityState.Added;
_db.SaveChanges();
Related
I have 2 related entities in EF Core (database first design from an existing database) and having trouble loading one-many relationship - it's a webapi ASP.NET core 1.0 application
Brand Entity
[Table("tblBranding")]
public class Brand {
[Key]
[Column("brandingId")]
public int BrandId { get; set; }
[Column("BrandingActive")]
public bool Active { get; set; }
[JsonIgnore]
[Column("DeadBrand")]
public bool DeadBrand { get; set; }
[Column("BrandingSiteTitle")]
public string Name { get; set; }
//navigation properties
public virtual ICollection<Event> Events { get; set; }
}
Event entity:
[Table("tblEvents")]
public class Event
{
public int EventId { get; set; }
[Column("eventActive")]
public bool Active { get; set; }
[Column("eventName")]
public string Name { get; set; }
public DateTime EventCloseDate {get;set;}
public int PaxAllocationLimit { get; set; }
//navigation properties
[Column("BrandingId")]
public int BrandId { get; set; }
public virtual Brand Brand { get; set; }
public virtual ICollection<Session> Sessions { get; set; }
}
code from for FLUID API in OnModelCreating in DbContext:
modelBuilder.Entity<Event>()
.HasOne(e => e.Brand)
.WithMany(b => b.Events).HasForeignKey(e=>e.BrandId);
public virtual DbSet<Brand> Brands { get; set; }
public virtual DbSet<Event> Events { get; set; }
code from BrandsController:
[HttpGet]
public IActionResult Get() {
//var brands = from b in _context.Brands
// where b.Active == true
// orderby b.BrandName
// select b;
var brands = _context.Brands.Include(e => e.Events).Where(b => b.Active == true).OrderBy(b => b.Name);
return new ObjectResult(brands);
}
code from EventsController
// GET: api/values
[HttpGet("{id:int?}")]
public IActionResult Get(int? id) {
var events = from e in _context.Events
where e.Active == true
orderby e.Name
select e;
if (!events.Any()) {
return HttpNotFound();
}
if (id != null) {
events = events.Where(e => e.EventId == id).OrderBy(e => 0);
if (events.Count() == 0) { return HttpNotFound(); }
return new ObjectResult(events);
}
else {
return new ObjectResult(events);
}
}
When I try to load brands through the API, I get an exception:
Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory: Information: Executed DbCommand (80ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [t].[EventId], [t].[EventCloseDate], [t].[eventActive], [t].[BrandingId], [t].[EventId1], [t].[eventName], [t].[PaxAllocationLimit]
FROM [tblEvents] AS [t]
INNER JOIN (
SELECT DISTINCT [e].[BrandingSiteTitle], [e].[brandingId]
FROM [tblBranding] AS [e]
WHERE [e].[BrandingActive] = 1
) AS [e] ON [t].[BrandingId] = [e].[brandingId]
ORDER BY [e].[BrandingSiteTitle], [e].[brandingId]
Microsoft.Data.Entity.Query.Internal.SqlServerQueryCompilationContextFactory: Error: An exception occurred in the database while iterating the results of a query.
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'EventId1'.
Apart from this, is there a way to load related entities without using the "Includes" ? If I do not use include and use the standard LINQ query, the related entities are loaded as NULL
UPDATE
I'm now getting an invalid column error - i noticed in my previous code I hadn't used virtual on the ICollection in brand
now i can't figure out why is it generating EventId1 column in the SQL
EF 7 version is 1.0.0-rc1-final
UPDATE-2
After playing around with the code the Exception changed to circular dependency exception in code given the exact same code as above - I don't know why it was generating the invalid column name earlier (EventId1)
Answering my own question here - figured it out-
the 2 entities used here, I've used fully defined relationships in the EF 7
- however the JSON serializer doesn not like that,as this createsa circular dependancy - Brand Contains Events List, and each event also contains the parent brand property -
so the solution here was to add [JsonIgnore] attribute to relationship properties on the child
updated Events class:
[Table("tblEvents")]
public class Event
{
public int EventId { get; set; }
[Column("eventActive")]
public bool Active { get; set; }
[Column("eventName")]
public string Name { get; set; }
public DateTime EventCloseDate {get;set;}
public int PaxAllocationLimit { get; set; }
//navigation properties
[JsonIgnore]
[Column("brandingId")]
public virtual int BrandId { get; set; }
[JsonIgnore]
public virtual Brand Brand { get; set; }
//public virtual ICollection<Session> Sessions { get; set; }
}
I am using Entity Framework and this is my view model:
public class UserDetailsModel:CityModel
{
public int Id { get; set; }
public string Fullname { get; set; }
}
public class VendorInCategoryModel
{
public int CategoryId { get; set; }
public int VendorId { get; set; }
public virtual CategoryMasterModel CategoryMaster { get; set; }
public virtual UserDetailsModel UserDetails { get; set; }
}
public class CategoryMasterModel
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
This is my query to fetch vendor details along with category details of particular vendor say v001:
UserDetailsModel workerDetails = context.UserDetails.
Where(d => d.Id == _vendorId).
Select(d => new UserDetailsModel
{
Id = d.Id,
Fullname = d.Fullname,
CategoryId = d.VendorInCategory.Select(v => v.CategoryId).FirstOrDefault(),
}).SingleOrDefault();
Here I have used FirstOrDefault to fetch categoryId (that is single value)
But I don't want to use FirstOrDefault as I have used in so many queries and it is giving me wrong output in some cases. So that the reason why I don't want to use FirstOrDefault.
When I have written SingleOrDefualt in place of FirstOrDefault it is throwing me error
that use FirstOrDefault.
So how to overcome this? Can anybody please help me?
It looks like maybe your outer select is capable of returning multiple results (e.g. if there are more than one UserDetailsModel with the same Id). If it returns multiple results then your call to .SingleOrDefault() will throw an exception as it expects only a single result or no results. See LINQ: When to use SingleOrDefault vs. FirstOrDefault() with filtering criteria for more details.
Models:
public class User
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
}
public class Resource
{
[Key]
public int ResourceId { get; set; }
public string ResourceName { get; set; }
public string ResourceDescription { get; set; }
}
public class UserResource
{
[Key, Column(Order=0)]
public int UserId { get; set; }
[Key, Column(Order=1)]
public int ResourceId { get; set; }
public int ResourceQuantity { get; set; }
}
I want to select "ResourceName" from Resource model and "ResourceQuantity" from UserResource model for a given "UserId". Also, once selected, do I need a brand new model to carry only those two specified columns?
Also note that UserResource model has a composite key so I am confused as to how to make the join... Is this right?
var userResources =
from r in imDB.Resources
join ur in imDB.UserResources
on r.ResourceId equals ur.ResourceId
select new { r.ResourceName, ur.ResourceQuantity };
Hence you're using Code first you can create your models are as below by using EF conventions.
public class User {
public int Id { get; set; }
public string UserName { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
}
public class Resource {
public int Id { get; set; }
public string ResourceName { get; set; }
public int ResourceQuantity { get; set; }
public virtual ICollection<User> Users {get;set;}
}
Then EF will generate your junction table is as UsersResources.You don't need to create additional model as you did.EF will look after that.
When using POCOs with EF, if you mark your navigation properties as
virtual you can use additional EF supports like Lazy Loading. So in
general use a virtual keyword in navigation properties considered to
be a good practice.
UPDATE
You may try something like below:
Method 1 : Method based syntax
imDB.Resources.Where(r => r.Users.Any(u => u.UserId == userId))
Method 2 : Query based syntax
from r in imDB.Resources
from u in r.Users
where u.UserId == userId
select r;
I hope this will help to you.
Models:
public class Status
{
public int Id { get; set; }
}
public class Podcast
{
public int Id { get; set; }
public virtual Status Status { get; set; }
}
The Podcast table has the StatusId column, and this column is a foreign key. In this case I've got the following error message: Invalid column name 'Status_Id'. Why? - Many times I faced that articles with such examples. This is the first question.
Ok, no problem - i've added an underscore character to these columns: Sttaus_Id and so on.
Now it seems that everything works fine, but when I modify my model by the following way:
public class Podcast
{
public int Id { get; set; }
public int Status_Id { get; set; }
public virtual Status Status { get; set; }
}
Now I get the following error: Invalid column name 'Status_Id1'.
Why? I can't use the DropDownListFor helper without these xx_id properies.
I believe the issue here is that you have created your DB first and created a column named StatusId for your FK reference but you haven't told EF that you are using a non-default column name for your FK.
the following will give you the structure you are after (ps i agree with your naming convention i personally dislike the _ in fk ids)
public class MyContext : DbContext
{
public DbSet<Podcast> Podcasts { get; set; }
public DbSet<Status> Status { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Podcast>().HasOptional(p => p.Status)
.WithMany().HasForeignKey(p => p.StatusId);
base.OnModelCreating(modelBuilder);
}
}
public class Status
{
public int Id { get; set; }
}
public class Podcast
{
public int Id { get; set; }
public int? StatusId { get; set; }
public virtual Status Status { get; set; }
}
The convention at least for the foreign key field is table name + field name, so in your case StatusId without the underscore. But I'm not sure why it says invalid column name Status_Id1.
Remove the underscore, and try again. If you still get an error message, please make an edit to your question with the results.
I've got CodeFirst collection defined as defined below.
For any given EmailOwnerId, I want to count the number of EmailDetailAttachments records exist without actually downloading all the images themselves.
I know I can do something like
var emailsToView = (from data in db.EmailDetails.Include("EmailDetailAttachments")
where data.EmailAccount.EmailOwnerId = 999
select data).ToList();
int cnt = 0;
foreach (var email in emailsToView)
{
cnt += email.EmailDetailAttachments.Count();
}
but that means I've already downloaded all the bytes of images from my far away server.
Any suggestion would be appreciated.
public class EmailDetail
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int EmailOwnerId {get;set;}
public virtual ICollection<ImageDetail> EmailDetailAttachments { get; set; }
..
}
public class ImageDetail
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLengthAttribute(256)]
public string FileName { get; set; }
[MaxLengthAttribute(256)]
public string ContentMimeType { get; set; }
public byte[] ImageDataBytes { get; set; }
public DateTime ImageCreation { get; set; }
}
The engine should be able to update this to a COUNT(*) statement.
var emailsToView = (from data in db.EmailDetails // no Include
where data.EmailAccount.EmailOwnerId = 999
select new {
Detail = data,
Count=data.EmailDetailAttachments.Count() }
).ToList();
But you'll have to verify if this produces the right (and more efficient) SQL.