I have the following entities in my context:
public class Asset
{
public int AssetId { get; set; }
public Registration Registration { get; set; }
[Required]
[Display(Name = "Asset Type")]
public AssetType AssetType { get; set; }
[Required]
[Range(Constants.SerialNumberStart, Constants.SerialNumberEnd)]
[DisplayFormat(DataFormatString = "{0:d8}")]
public int SerialNumber { get; set; }
[Required]
[Range(Constants.EquipNumberStart, Constants.EquipNumberEnd)]
[DisplayFormat(DataFormatString = "{0:d12}")]
public long EquipNumber { get; set; }
[Required]
[Display(Name = "Profile")]
[Range(Constants.ProfileStart, Constants.ProfileEnd)]
[DisplayFormat(DataFormatString = "{0:d2}")]
public int Profile { get; set; }
}
public class AssetType
{
public int AssetTypeId { get; set; }
public List<Asset> Asset { get; set; }
[Required]
[Display(Name = "Asset Type")]
[StringLength(40)]
public string AssetTypeFullName { get; set; }
[Required]
[Display(Name = "Asset Alias")]
[StringLength(8)]
public string AssetTypeShortName { get; set; }
}
I've seeded my database and everything looks fine, the AssetType foreign key properly shows the index into my AssetType table data.
But when I try to get the data ready for the View in the code below, the AssetType key/data is null.
public ActionResult Index()
{
Logger.Debug("Index");
RegistrationServerContext dbNotLazy = new RegistrationServerContext();
return View(dbNotLazy.Assets.ToList());
}
When I set a break point and examine my dbNotLazy.Asset data, the AssetType foreign key is null.
I thought this might have to do with Lazy Loading, but as you can see, I create a new context before my View call. What might I be doing wrong?
You may need to use an Include - change
return View(dbNotLazy.Assets.ToList());
to
return View(dbNotLazy.Assets.Include("AssetType").ToList());
Lazy loading doesn't always seem to work immediately.
Related
One display should have many media(images, videos) in my project. I'm using Entity Framework Core to build my database, and CRUD with my API Controller.
I designed my Model classes as such:
[Table("Displays")]
public class Display : ConcurrencyCheck
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage = "{0} skal udfyldes!")]
[Display(Name = "Display navn")]
public string Name { get; set; }
[Display(Name = "Display tændt")]
public bool IsOn { get; set; }
[Display(Name = "Display beskrivelse")]
public string Description { get; set; }
public IEnumerable<Video> Videos { get; set; }
public IEnumerable<Image> Images { get; set; }
}
public abstract class Media : ConcurrencyCheck
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage = "{0} skal udfyldes!")]
[Display(Name = "Medie navn")]
public string Name { get; set; }
[Display(Name = "Medie beskrivelse")]
public string Description { get; set; }
[Display(Name = "Medie filtype")]
public string FileType { get; set; }
[Required(ErrorMessage = "{0} skal udfyldes!")]
[Display(Name = "Medie filsti")]
public string FilePath { get; set; }
public int? DisplayId { get; set; }
[ForeignKey("DisplayId")]
public Display Display { get; set; }
}
[Table("Videos")]
public class Video : Media
{
[Display(Name = "Frames")]
public int Frames { get; set; }
[Display(Name = "Filsti på undetekster")]
public string SubtitlesPath { get; set; }
[Display(Name = "Filsti på thumbnail")]
public string ThumbnailPath { get; set; }
}
[Table("Images")]
public class Image : Media
{
}
public abstract class ConcurrencyCheck
{
[Timestamp]
public byte[] RowVersion { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy HH:mm}", ApplyFormatInEditMode = true)]
public DateTime CreatedDate { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy HH:mm}", ApplyFormatInEditMode = true)]
public DateTime? UpdatedDate { get; set; }
}
And my API controllers are scaffolded with 'API Controller with actions, using Entity Framework'.
Currently in the api-controller 'DisplaysController', I don't see the .Include(x => x.Media), though I read somewhere it's used? One display should have many media(images, videos).
Should I include it somehow somewhere, or does it do that automatically by the models I have?
scaffolded with API Controller with actions, using Entity Framework just provide the most basic five database operation methods -- select , select by id, update, add and delete. Its purpose is to help users build basic crud faster and more easily. You can add your own code on the default code template.
The default code template
Add your own code
I'm using EF core, and I have a many-to-many relationship between two entity
IotaProject <--> User
Here's entities & dto related to the question
public class IotaProject
{
[Key]
public int Id { get; set; }
[Required]
public string ProjectName { get; set; }
[Required]
public DateTime Create { get; set; }
public ICollection<ProjectOwnerJoint> Owners { get; set; } = new List<ProjectOwnerJoint>();
}
public class ProjectOwnerJoint
{
public int IotaProjectId { get; set; }
public IotaProject IotaProject { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User
{
[Key]
public int Id { get; set; }
[Required]
public string FullName { get; set; }
[Required]
public string ShortName { get; set; }
[Required]
public string Email { get; set; }
public ICollection<ProjectOwnerJoint> OwnedProjects { get; set; } = new List<ProjectOwnerJoint>();
}
public class ApplicationDbContext : DbContext
{
public DbSet<IotaProject> IotaProjects { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<ProjectOwnerJoint> ProjectOwnerJoint { get; set; }
}
public class IotaProjectDisplayDto
{
public int Id { get; set; }
public string ProjectName { get; set; }
public DateTime Create { get; set; }
public UserMinDto Owner { get; set; }
public int Count { get; set; }
public IEnumerable<UserMinDto> Reviewers { get; set; }
}
public class UserMinDto
{
public int Id { get; set; }
public string FullName { get; set; }
public string ShortName { get; set; }
}
Following LINQ is the problem, the LINQ purpose is to convert IotaProject to IotaProjectDisplayDto, and key part is that Owners property of IotaProject is ICollection and Owner property in IotaProjectDisplayDto is just one single element UserMinDto, so I only need to get the first element of IotaProject's Owners and that's FirstOrDefault() comes.
IEnumerable<IotaProjectDisplayDto> results = _db.IotaProjects.Select(x => new IotaProjectDisplayDto
{
Id = x.Id,
ProjectName = x.ProjectName,
Create = x.Create,
Owner = x.Owners.Select(y => y.User).Select(z => new UserMinDto { Id = z.Id, FullName = z.FullName, ShortName = z.ShortName }).FirstOrDefault()
});
return results;
it throws run-time exception
Expression of type 'System.Collections.Generic.List`1[ToolHub.Shared.iota.UserMinDto]' cannot be used for parameter
of type 'System.Linq.IQueryable`1[ToolHub.Shared.iota.UserMinDto]'
of method 'ToolHub.Shared.iota.UserMinDto FirstOrDefault[UserMinDto](System.Linq.IQueryable`1[ToolHub.Shared.iota.UserMinDto])' (Parameter 'arg0')
I'm guessing it's probably related to deferred execution, but after read some posts, I still can't resolve it.
Any tips would be appreciated.
Right now, the only way I can get this work is I change type of Owner property in IotaProjectDisplayDto into IEnumrable, which will no longer need FirstOrDefault() to immediate execution. And later on, I manually get the first element in the client to display.
This issue happened in Microsoft.EntityFrameworkCore.SqlServer 3.0.0-preview7.19362.6
I end up downgrade to EF core stable 2.2.6 as Ivan suggested in comment, and everything works fine.
I am issuing a very strange scenario using Code first with existing database and asp.net identity entity framework. I have a simple userprofile model
[Table("CSUserProfile")]
public partial class UserProfile
{
[Key]
public string Id { get; set; }
[Required]
[Display(Name = "FirstName")]
public string FirstName { get; set; }
[Required]
[Display(Name = "LastName")]
public string LastName { get; set; }
[Required]
[Display(Name = "Phone")]
public string Phone { get; set; }
[Required]
public string Email { get; set; }
[Required]
[Display(Name = "Location")]
public string Location { get; set; }
[Required]
[Display(Name = "HomeTown")]
public string Hometown { get; set; }
public byte[] BlobData { get; set; }
[ForeignKey("fPersonLinkGID")]
public virtual List<ProfilePic> ProfilePic { get; set; }
}
and an image profile pic
[Table("CSProfilePic")]
public partial class ProfilePic
{
[Key]
public Guid? GID { get; set; }
public string fPersonLinkGID { get; set; }
public byte[] BlobData { get; set; }
}
the foreign key is the fPersonLinkGID. everything works fine but my problem is that if i want an one-to-one relation between the userprofile and the image like this
public virtual ProfilePic ProfilePic { get; set; }
(which is the correct scenario) I am getting this strange exception :
The ForeignKeyAttribute on property 'ProfilePic' on type 'eUni.Model.Application.UserProfile' is not valid. The foreign key name 'fPersonLinkGID' was not found on the dependent type 'eUni.Model.Application.UserProfile'. The Name value should be a comma separated list of foreign key property names.
I can not understand why I am getting that exception
You could read this answer. It introduces how to configure one to one relationship by HasRequired and WithOptional.
As for me, I will create one to one relationship by following way.
public class Store {
[Key]
public long Id { get; set; }
public virtual Item TheItem { get; set; }
// ....
}
public class Item {
// It is FK, and also PK.
[Key, ForeignKey("TheStore")]
public long Id { get; set; }
// The same string in the ForeignKey attribute. Ex: ForeignKey("TheStore")
public virtual Store TheStore { get; set; }
// ....
}
I have some problems when updating my model. This is my update code:
public void Update(Class #class)
{
var updatedClass = context.Classes.Where(c => c.ClassId == #class.ClassId).FirstOrDefault();
updatedClass.ClassPriceTypeId = #class.ClassPriceTypeId;
updatedClass.ClassType = #class.ClassType;
updatedClass.Name = #class.Name;
updatedClass.Title = #class.Title;
updatedClass.MetaTag = #class.MetaTag;
updatedClass.MetaDescription = #class.MetaDescription;
updatedClass.UrlSafe = #class.UrlSafe;
updatedClass.Header = #class.Header;
updatedClass.Margin = #class.Margin;
updatedClass.ImageName = #class.ImageName;
updatedClass.GroupId = #class.GroupId;
updatedClass.IsPublished = #class.IsPublished;
context.SaveChanges();
}
First problem is that I have made LazyLoadingEnabled=false but after fetching updatedClass the relational properties like Group is not null.
Second problem is that in some of #class objects I can easily update my entity but in some others I see this error:
The operation failed: The relationship could not be changed because
one or more of the foreign-key properties is non-nullable. When a
change is made to a relationship, the related foreign-key property is
set to a null value. If the foreign-key does not support null values,
a new relationship must be defined, the foreign-key property must be
assigned another non-null value, or the unrelated object must be
deleted.
Update
This is Class model:
public class Class
{
public int ClassId { get; set; }
public int GroupId { get; set; }
public int ClassPriceTypeId { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string MetaTag { get; set; }
public string MetaDescription { get; set; }
public string UrlSafe { get; set; }
public string Header { get; set; }
public string ImageName { get; set; }
public int Margin { get; set; }
public string ClassType { get; set; }
public bool IsPublished { get; set; }
public virtual Group Group { get; set; }
public virtual List<Product> Products { get; set; }
public virtual List<Comparing.Model.Price.Price > Prices { get; set; }
public virtual ClassPriceType.ClassPriceType ClassPriceType { get; set; }
public virtual List<Garanty> Garanties { get; set; }
public virtual List<PhoneModel> PhoneModels { get; set; }
public virtual List<ClassPartner> ClassPartners { get; set; }
public virtual List<Content> Contents { get; set; }
}
And this is Group model:
public class Group
{
public int GroupId { get; set; }
public int SectionId { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string MetaTag { get; set; }
public string MetaDescription { get; set; }
public string UrlSafe { get; set; }
public string Header { get; set; }
public string ImageName { get; set; }
public bool IsPublished { get; set; }
public virtual Section Section { get; set; }
public virtual List<Class> Classes { get; set; }
}
Can anyone help me about the problem?
I guess, you are trying to update a primary key field which is having a relation ship with other foreign key with not null constraint. I guess you need to use update cascade.
I am new to EF and am having trouble figuring how to set up relationship between my main table Investors, with contact information, and a table Notes which can have many notes per investor. Here are the models:
public class Investor
{
public int Id { get; set; }
public string Name { get; set; }
public string Company { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Cell { get; set; }
public string Fax { get; set; }
[Display(Name="Address 1")]
public string Address1 { get; set; }
[Display(Name = "Address 2")]
public string Address2 { get; set; }
public string City { get; set; }
[StringLength(2, ErrorMessage = "State must be 2 characters")]
public string State { get; set; }
public string Zip { get; set; }
public string ContactTableId { get; set; }
[ForeignKey("ContactTableId, ContactId")]
public virtual List<Note> Notes { get; set; }
}
public class Note
{
[Key]
[Column(Order = 0)]
public string ContactTableId { get; set; }
[Key]
[Column(Order = 1)]
public int? ContactId { get; set; }
public string note { get; set; }
public DateTime? DateCreated { get; set; }
}
My attempt as setting this up, as above, generated the error 'The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.' on the statement:
public ActionResult Index()
{
return View(db.Investors.ToList());
}
in the controller. How do I set this up to make it pull the Notes automagically.
The foreign key is not "ContactTableId, ContactId", it is the single field Investor_Id in table Note (or Notes). EF thinks you try to map the single key to two field and coins this somewhat elusive exception message. But just remove the ForeignKey attribute and EF will use the foreign key field in Note.