value cannot be null in Entity Sql Statement - c#

My News.cs class has a one to many relationship with Comment.cs as defined below
public class News
{
public int NewsId { get; set; }
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "Details")]
public string Details { get; set; }
public DateTime DateCreated { get; set; }
public int AppUserId { get; set; }
[ForeignKey("AppUserId")]
public virtual AppUser AppUser { get; set; }
public ICollection<Comment> Comment { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
public string CommentText { get; set; }
public DateTime DateCreated { get; set; }
public int AppUserId { get; set; }
public int? NewsId { get; set; }
[ForeignKey("AppUserId")]
public virtual AppUser AppUser { get; set; }
[ForeignKey("NewsId")]
public virtual News News { get; set; }
}
I have a controller action where i am trying to fetch one News item alongside all its comments so i set up two viewModels like this
public class CommentVM
{
public string CommentText { get; set; }
public DateTime DateCreated { get; set; }
public string Author { get; set; }
}
public class NewsCommentsVM
{
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "Details")]
public string Details { get; set; }
public DateTime DateCreated { get; set; }
public string Author { get; set; }
public List<CommentVM> Comments { get; set; }
}
In my Controller action i have
public ActionResult Details(int? id)
{
UOW _unit = new UOW();
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
News news = _unit.NewsRepository.GetByID(id);
if (news == null)
{
return HttpNotFound();
}
var model = new NewsCommentsVM()
{
Title = news.Title,
Details = news.Details,
DateCreated = news.DateCreated,
Author = news.AppUser.FirstName
Comments = news.Comment.Select(c => new CommentVM()
{
CommentText = c.CommentText,
Author = c.AppUser.Email,
DateCreated = c.DateCreated
}).ToList()
};
return View(result);
}
The problem is that the debugger is showing that Comment is returning Null whereas in the database there are related comments to that particular news item so i'm getting the error
Value cannot be null. Parameter: source
I've been able to use this code in another project without issues.

I think the problem is because you need to change the Comments collection property as virtual. If you want that related entities be lazy loaded, you need to follow this requirements:
public class News
{
//...
public virtual ICollection<Comment> Comment { get; set; }
}
Now,If you have disabled lazy loading, another option could be using the Include extension method in your query when you need to find a particular news:
int id=3;
var specificNews=context.News.Include(n=>n.Comment).FirstOrDefault(n=>n.Id==id);
This way the related entity will be included in the query result

Related

EF Code first, table relationship problem

I get an error in the comments model in relations, I'm waiting for a practical answer, it seems like there is nothing difficult. I use the picture model easily in the article model. I thought of using this table in the auhor model, but I am stuck in relationships, what should I do?
public class Article
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Detail { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public bool IsActive { get; set; } = false;
// Scaler properties
public int AuthorId { get; set; }
public int CategoryId { get; set; }
// Navigation properties
public virtual Picture Picture { get; set; } = new Picture();
public virtual Author Author { get; set; } = new Author();
public virtual Category Category { get; set; } = new Category();
public virtual ICollection<Comment>? Comments { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Surname { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public DateTime DateOfBirth { get; set; }
public DateTime CreatedAt { get; set; }
// Navigation properties
public virtual ICollection<Article>? Articles { get; set; }
public virtual ICollection<Comment>? Comments { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public byte SortBy { get; set; }
// Navigation property
public virtual ICollection<Article>? Articles { get; set; }
}
public class Comment
{
public int Id { get; set; }
public string Content { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public bool IsActive { get; set; } = false;
// Scaler properties
public int ArticleId { get; set; }
public int AuthorId { get; set; }
// Navigation properties
public virtual Article Article { get; set; } = new Article();
public virtual Author Author { get; set; } = new Author();
}
public class Picture
{
public int Id { get; set; }
public string Src { get; set; } = string.Empty;
public string Alt { get; set; } = string.Empty;
public string? Title { get; set; }
// Scaler property
public int ArticleId { get; set; }
// Navigation property
public virtual Article Article { get; set; } = new Article();
}
This is the error:
Introducing FOREIGN KEY constraint 'FK_Comments_Authors_AuthorId' on
table 'Comments' may cause cycles or multiple cascade paths. Specify
ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN
KEY constraints. Could not create constraint or index. See previous
errors
Are there any problems in other relationships? we can discuss

Automapper Mapping Exception

I am trying to build a simple application where I can store and retrieve some details about some devices and the users of them, like an inventory. But when I try to display the list of devices with their owners, Automapper throws this error:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
I don't understand what I am doing wrong here. How can I deal with this?
Startup.cs
builder.Services.AddAutoMapper(typeof(MapConfig));
builder.Services.AddControllersWithViews();
var app = builder.Build();
MapConfig.cs
public class MapConfig : Profile
{
public MapConfig()
{
CreateMap<Asset, AssetVM>().ReverseMap();
CreateMap<AppUser, AppUsersVM>().ReverseMap();
}
}
Asset.Cs
public class Asset
{
public int Id { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public string? ProductNumber { get; set; }
public string? SerialNumber { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
public bool IsAssigned { get; set; }
public string? ISN { get; set; }
public string Status { get; set; }
public bool IsInsured { get; set; }
public string Condition { get; set; }
[ForeignKey("UserId")]
public AppUser AppUser { get; set; }
public string? UserId { get; set; }
}
AssetVM
public class AssetVM
{
public int Id { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
[Display(Name ="Product Number")]
public string? ProductNumber { get; set; }
[Display(Name ="Serial Number")]
public string? SerialNumber { get; set; }
[Display(Name ="Date Created")]
[DataType(DataType.Date)]
public DateTime DateCreated { get; set; }
[Display(Name = "Date Modified")]
[DataType(DataType.Date)]
public DateTime DateModified { get; set; }
[Display(Name ="Assigned")]
public bool IsAssigned { get; set; }
public string? ISN { get; set; }
[Required]
public string Status { get; set; }
[Display(Name ="Has Insurance")]
public bool IsInsured { get; set; }
[Required]
public string Condition { get; set; }
public string? UserId { get; set; }
public SelectList? AppUsersList { get; set; }
public AppUsersVM AppUsers { get; set; }
}
This is how I get and map the data that is to be displayed on the page:
public async Task<AssetVM> GetAssets()
{
var asset = await context.Assets.Include(q => q.AppUser).ToListAsync();
var model = mapper.Map<AssetVM>(asset);
return model;
}
And finally I return the result of GetAssets method to the view in my controller:
var model = await assetRepository.GetAssets();
return View(model);
Well, I found what I'm doing wrong. This is what I've done:
Since I was getting a list after querying the database in my GetAssets method, I had to change my mapping to:
var model = mapper.Map<List<AssetVM>>(asset);
And to be able to return this model, I also had to change my method declaration to:
public async Task<List<AssetVM>> GetAssets()
This changes made it work, except I didn't get the details of the user that is using that asset. And this was due to a typo in my AssetVM viewmodel.
public AppUsersVM AppUser { get; set; }
Those were all the changed I had to do. Still have a looong way to be a competent programmer so I'd be glad if you let me know if I have any flaws in my logic or any recommendations at all.

How to create a relation between existing entities in EF core?

I have a case scenario with two tables References and Products alreading containing many entries which can be dynamically related on demand.
public class Reference
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ReferenceId { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public virtual ICollection<Product> ManyProducts { get; set; }
public Reference() {}
}
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[ForeignKey("Reference")]
public Guid ReferenceId { get; set; }
public virtual Reference OneReference { get; set; }
public Product() {}
}
When a user ask to link a reference to a product I simply do :
product.ReferenceId = reference.ReferenceId ;
await context.SaveChangesAsync() ;
The entry in Products table is updated correctly, but when I try to access a reference's related data, it does not retrieve any ?? After eager loading :
var reference = await context.References
.Include(r => r.ManyProducts)
.SingleAsync(r => r.ReferenceId == referenceId) ;
or explicit loading :
var reference = await context.References.FindAsync(referenceId) ;
await context.Entry(reference).Collection(s => s.ManyProducts).LoadAsync() ;
reference.ManyProducts is empty. So I have to do something like this :
var reference = await context.References.FindAsync(referenceId) ;
var products = await context.Products.Where(l => l.ReferenceId == referenceId).ToListAsync() ;
result.ManyProducts = products ;
which works fine, but I would like to understand why ?
I´m using DataAnnotation
Sample
public class spread
{
[Key]
public int spreadid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange origem")]
public virtual exchange exchange { get; set; } // One to one
[ForeignKey("spreadid")]
public virtual ICollection<spreadhelper> spreadhelper { get; set; } // One to many
}
public class spreadhelper
{
[Key]
public int spreadhelperid { get; set; }
[Required]
public int spreadid { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange")] // One to one
public virtual exchange exchange { get; set; }
[Required, Range(0, 200)]
public decimal spreadvalue { get; set; }
}
one to one - sample
public class exchange
{
[Key]
public int exchangeid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required, MaxLength(50)]
public string name { get; set; }
[MaxLength(128)]
public string token { get; set; }
}
One to many sample

Entity to model mapping in LINQ

I have article and author classes.
Fetch articles like so and map entity to model:
public List<Model.Article> GetArticleList() {
using (var db = new ArticlesContext()) {
return db.Articles.Select(t => new Model.Article() {
Author = MapUserEntityToModel(db.Users.FirstOrDefault(u => u.UserID == t.UserID))
Title = t.Title,
Teaser = t.Teaser
// etc
}).ToList();
}
}
This doesn't work because LINQ can't run that function at run-time. What's the simplest and cleanest way to do the mapping?
Here are models:
namespace Model {
public class Article {
public string Title { get; set; }
public string Teaser { get; set; }
public User Author { get; set; }
public DateTime DateAdded { get; set; }
}
public class User {
public string DisplayName { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public string PasswordHash { get; set; }
}
}
Here are entities:
namespace MyProj {
public class Article {
[Key]
public int ArticleID { get; set; }
public string Title { get; set; }
public string Teaser { get; set; }
public int UserID { get; set; }
public DateTime DateAdded { get; set; }
}
public class User {
[Key]
public int UserID { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public string PasswordHash { get; set; }
}
public class ArticleContext : DbContext {
public ArticleContext() : base("name=conn") {
public DbSet<Article> Articles { get; set; }
public DbSet<User> Users { get; set; }
}
}
}
Before continue, map your relationship in a navigation property:
public class Article {
[Key]
public int ArticleID { get; set; }
public string Title { get; set; }
public string Teaser { get; set; }
[ForeignKey("UserID")]
public virtual User Author {get; set; } // navigation property
public int UserID { get; set; }
public DateTime DateAdded { get; set; }
}
And then just project your navigation property to his equivalent Model:
public List<Model.Article> GetArticleList() {
using (var db = new ArticlesContext()) {
return db.Articles.Select(t => new Model.Article() {
Author = new Model.User {
DisplayName = t.User.DisplayName,
Email = t.User.Email,
Website = t.User.Website,
PasswordHash = t.User.PasswordHash
},
Title = t.Title,
Teaser = t.Teaser
// etc
}).ToList();
}
}
You don't need to do anything, just return db.Articles directly:
using Model;
public List<Article> GetArticleList() {
using(var db = new ArticlesContext()) {
return db.Articles.ToList();
}
}
Assuming your EF model is set-up correctly with Foreign Keys, your Article type will have a lazily-evaluated Author property which will return a User object when accessed.

Error with Entity Framework 4 and MVC 3

I have a database with 3 tables:
Subjects
Members
Topics
Then I added the connection string to web.config and created an EF with the following classes:
namespace MySite.Models
{
public class MySiteDBModel : DbContext
{
public DbSet<Topic> Topics { get; set; }
public DbSet<Subject> Subjects { get; set; }
public DbSet<Member> Members { get; set; }
public DbSet<TopicDataModel> TopicDataModel { get; set; }
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class Topic
{
[Key]
public int TopicID { get; set; }
public int SubID { get; set; }
public int MemberID { get; set; }
public string TDate { get; set; }
public string Title { get; set; }
public string FileName { get; set; }
public int Displays { get; set; }
public string Description { get; set; }
public virtual Subject Subject { get; set; }
public virtual Member Member { get; set; }
public virtual ICollection<TopicView> TopicView { get; set; }
}
public class Subject
{
[Key]
public int SubID { get; set; }
public string SubName { get; set; }
public virtual ICollection<Topic> Topic { get; set; }
}
public class Member
{
[Key]
public int MemberID { get; set; }
public string FLName { get; set; }
public string Email { get; set; }
public string Pwd { get; set; }
public string About { get; set; }
public string Photo { get; set; }
public virtual ICollection<Topic> Topic { get; set; }
}
public class TopicDataModel
{
[Key]
public int TopicID { get; set; }
public string SubName { get; set; }
public string FLName { get; set; }
public string TDate { get; set; }
public string Title { get; set; }
public int Displays { get; set; }
public string Description { get; set; }
}
}
Now when I am trying to query the database with the this code:
public ActionResult Index()
{
var topics = from t in db.Topics
join s in db.Subjects on t.SubID equals s.SubID
join m in db.Members on t.MemberID equals m.MemberID
select new TopicDataModel()
{
TopicID = t.TopicID,
SubName = s.SubName,
FLName = m.FLName,
TDate = t.TDate,
Title = t.Title,
Displays = t.Displays,
Description = t.Description
};
return View(topics.ToList());
}
I got this Error:
The model backing the 'MySiteDBModel' context has changed since the
database was created. Either manually delete/update the database, or
call Database.SetInitializer with an IDatabaseInitializer instance.
For example, the DropCreateDatabaseIfModelChanges strategy will
automatically delete and recreate the database, and optionally seed it
with new data.
Please help me!!!!!!
You need to set some controls on how EF is handling changes to your data model. Julie Lerman has a good blog post on Turning Off Code First Database Initialization Completely.
Also, here is a good overview - Inside Code First Database Initialization

Categories