DataContext is missing properties in where statement - asp.net-mvc

Could some tell me why I have no properties in my where statements after using a select statement for e.g.
db.Select(x => x.Lft).Where(x => x.DepartmentId == id);
// missing properties in the where clause
And could you help me correct my code to implement it please leave me an example of what to do to implement this thanks
Classes:
public class Department
{
public Department()
{
Products = new List<Product>();
}
public long DepartmentId { get; set; }
[Required(ErrorMessage="Please enter a name for the departments.")]
[DataType(DataType.Text)]
public string Name { get; set; }
[DataType(DataType.Text)]
[Required(ErrorMessage = "Please enter a valid url for the department.")]
public string Url { get; set; }
public int Lft { get; set; }
public int Rgt { get; set; }
public bool MenuItem { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
my DataContext class
internal class DepartmentsTypeConfiguration : EntityTypeConfiguration<Department>
{
public DepartmentsTypeConfiguration()
{
Property(department => department.DepartmentId)
.HasColumnName("DepartmentId")
.HasDatabaseGeneratedOption(databaseGeneratedOption: DatabaseGeneratedOption.Identity);
Property(department => department.Name)
.HasColumnName("Name")
.IsRequired();
HasKey(key => key.DepartmentId)
.HasMany(x => x.Products)
.WithRequired(x => x.Department)
.WillCascadeOnDelete(true);
}
}
public class LeapFrogDataContext : DbContext
{
public DbSet<Department> Departments { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ProductSpecification> ProductSpecifications {get; set;}
public DbSet<Specification> Specifications { get; set; }
/**/
static LeapFrogDataContext()
//: base("name=LeapFrogDataConnection")
{
//Database.SetInitializer(new LeapFrogInitializer());
//Database.SetInitializer(new DropCreateDatabaseIfModelChanges<LeapFrogDataContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new DepartmentsTypeConfiguration());
modelBuilder.Configurations.Add(new ProductsTypeConfiguration());
modelBuilder.Configurations.Add(new SpecificationsTypeConfiguration());
modelBuilder.Configurations.Add(new ProductSpecificationsTypeConfiguration());
base.OnModelCreating(modelBuilder);
}
}

db.Select(x => x.Lft) returns a list of int so in the where clause you will not access any property.
I guess you may switch select and where to achieve what you want. Assume db is the actual context.
db.Where(x => x.DepartmentId == id).Select(x => x.Lft)
That's a bit weird. Normally it should look like
db.context.Departments.Where(x => x.DepartmentId == id).Select(x => x.Lft)

Related

EF6 Code first Composite Foreign key with Fluent API

I am having trouble creating One-one(zero) Foreign key relationship on code first EF6 fluent API
My Entities are
public class Invoice
{
public int AccountID { get; set; }
public int InvoiceID { get; set; }
public decimal Amount { get; set; }
public Refund Refund { get; set; }
internal static void ConfigureModel(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Invoice>()
.HasKey(e => new { e.AccountID, e.InvoiceID });
}
}
public class Refund
{
public int AccountID { get; set; }
public int RefundID { get; set; }
public decimal Amount { get; set; }
public int InvoiceID { get; set; }
public Invoice Invoice { get; set; }
internal static void ConfigureModel(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Refund>()
.HasKey(e => new { e.AccountID, e.RefundID });
modelBuilder.Entity<Refund>()
.HasRequired(e => e.Invoice )
// .HasForeignKey(e => new { e.AccountID, e.InvoiceID});
}
}
I can't define the composite foreign key on Refund table using fluent API
If I change the
public Refund Refund { get; set; }
to
public ICollection<Refund> Refund{ get; set; }
Then I can add this relation as
modelBuilder.Entity<Refund>()
.HasRequired(e => e.Invoice)
.WithMany(e => e.Refund)
.HasForeignKey(e => new { e.AccountID, e.InvoiceID});

Want to join two tables on primary key, display the results in one view

IQueryable<Product> product = objContext.Set<Product>().Include(p =>
p.Categories.Name).Where(p => p.Id == 2);
As per the current view, I'm getting an error. It says add other model with their properties. i.e. to include Category model and corresponding Name property.
#model IEnumerable<>crudOneToMany.Models.Product>
using viewmodel, is it possible to join two tables?
View
Error
A specified Include path is not valid. The EntityType 'crudOneToMany.Models.Category' does not declare a navigation property with the name 'Name'.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CategoryId { get; set; }
public virtual Category Categories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
public class ProductDBContext : DbContext
{
public ProductDBContext()
: base("ProductDBContext")
{
}
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasRequired(o => o.Categories).WithMany(o => o.Products).HasForeignKey(o => o.CategoryId);
base.OnModelCreating(modelBuilder);
}
}
Your problem is here:
.Include(p => p.Categories.Name)
Instead you should write .Include(p => p.Categories)
This means that in output there will be loaded Categories navigation collection to product.
Name is simple string property (is not navigation property so it should not be included)
Here is the proposed ViewModel for you.
ProductViewModel.cs
public class ProductViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "required")]
public string ProductName { get; set; }
public Category Category { get; set; }
public ICollection<Category> Categories { get; set; }
}

EF7 Getting null values for entity's collection of entities which are many to many

I am getting null values for the collection of entities nested in my top entity. How do I properly write my LINQ query so that these values aren't null??
I am using Entity Framework 7 and MVC 6 Here are my classes:
My models:
public class WorkStation
{
public Id { get; set; }
public string Name{ get; set; }
public ICollection<PersonWorkStation> PersonWorkStations{ get; set; }
}
public class Person
{
public Id { get; set; }
public string FirstName { get; set; }
public ICollection<PersonWorkStation> PersonWorkStations{ get; set; }
}
public class PersonWorkStation
{
public int Id { get; set; }
public int PersonId { get; set; }
public Person Person { get; set; }
public int WorkStationId { get; set; }
public WorkStation WorkStation { get; set; }
}
My DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PersonWorkStation>()
.HasKey(op => new { op.Id });
modelBuilder.Entity<PersonWorkStation>()
.HasOne(pt => pt.Person)
.WithMany(p => p.PersonWorkStation)
.HasForeignKey(pt => pt.PersonId);
modelBuilder.Entity<PersonWorkStation>()
.HasOne(pt => pt.WorkStation)
.WithMany(t => t.PersonWorkStation)
.HasForeignKey(pt => pt.WorkStationId);
base.OnModelCreating(modelBuilder);
}
So with that being said, when I bring back a person, and look at the "PersonWorkStation"s collection, the WorkStation property is null. How can I bring back that entity?
Here is how I am retrieving the data:
var person = _context.Persons
.Include(p => p.PersonWorkStation)
.FirstOrDefault(p => p.Id == 1);
return person;
Again, the person.PersonWorkStations.Workstation entity is null for all items in the person.PersonWorkStations collection. How do I return this entity?
Thanks!
I have found the answer, I needed to add this line:
var person = _context.Persons
.Include(p => p.PersonWorkStation)
.ThenInclude(p => p.WorkStation)
.FirstOrDefault(p => p.Id == 1);
return person;

EF Code First - Populating data in Many to Many

I'm new to ASP.Net MVC and want to create a simple Blog project, therefore I have two entity posts and categories. each post can belong to many categories and each category can belong to many posts.
Models.cs
public class Category
{
[Key]
public int CategoryId { get; set; }
public int? ParentId { get; set; }
public virtual Category Parent { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual ICollection<News> News { get; set; }
public Category()
{
News = new List<News>();
}
}
public class News
{
[Key]
public int NewsId { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string Content { get; set; }
public string Source { get; set; }
public string SourceURL { get; set; }
public string Images { get; set; }
public string Password { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? ModifiedAt { get; set; }
public DateTime? DeletedAt { get; set; }
public string CreatedBy { get; set; }
public string DeletedBy { get; set; }
public virtual PublishPeriod PublishPeriodId { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public News()
{
Categories = new List<Category>();
}
}
ModelsMap.cs
public class CategoryMap:EntityTypeConfiguration<Category>
{
public CategoryMap()
{
Property(one => one.Title).HasMaxLength(100).IsRequired();
HasOptional(x => x.Parent).WithMany().HasForeignKey(x => x.ParentId);
}
}
public class NewsMap:EntityTypeConfiguration<News>
{
public NewsMap()
{
Property(x => x.CreatedBy).HasMaxLength(150);
Property(x => x.DeletedBy).HasMaxLength(150);
Property(x => x.Title).IsRequired().HasMaxLength(150);
Property(x => x.Summary).IsRequired();
Property(x => x.Content).IsRequired().HasColumnType("ntext");
Property(x => x.CreatedAt).HasColumnType("datetime");
Property(x => x.Password).IsOptional().HasMaxLength(128);
Property(x => x.DeletedAt).IsOptional();
Property(x => x.ModifiedAt).IsOptional();
HasMany(x => x.Categories).WithMany(x => x.News).Map(x =>
{
x.ToTable("NewsCategories");
x.MapLeftKey("News_NewsId");
x.MapRightKey("Category_CategoryId");
});
}
}
And DB Context
public DbSet<Category> Categories { get; set; }
public DbSet<News> News { get; set; }
public DbSet<PublishPeriod> PublishPeriod { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new CategoryMap());
modelBuilder.Configurations.Add(new NewsMap());
modelBuilder.Configurations.Add(new PublishPeriodMap());
I have a create view for posts that displays categories in a list with checkboxs and each checkbox value is category's ID. How can I insert or update posts and keep relation between post and categories.
NewsController
//
// POST: /Admin/News/Create
[HttpPost]
public ActionResult Create(News news, List<string> Category)
{
ViewBag.Categories = catRepository.All.OrderBy(x => x.Title);
if (ModelState.IsValid)
{
foreach (var item in Category)
{
news.AddCategory(catRepository.Find(int.Parse(item)));
}
news.CreatedAt = DateTime.Now;
news.CreatedBy = "M.Hesabi";
newsRepository.InsertOrUpdate(news);
newsRepository.Save();
return RedirectToAction("Index");
}
else
{
return View();
}
}
UPDATE: I created a method in News Model as #DanS said and edited my controller.
I'd recommend creating a method on the News class:
public void AddCategory(Category category) {
Categories.Add(category);
category.News.Add(this);
}
From your Controller you can then add each selected Category to the News instance, and then add the News to the DbContext prior to calling SaveChanges. This may depend, however, on how your repositories make use of the context -- in that if they open their own, instead of accessing a shared context, you might have to attach the categories to the News repository's context prior to saving. Hopefully this helps...
Update
IEntityChangeTracker error:
It appears as if MVCScaffolding uses a separate context for each repository. As mentioned, having separate contexts can lead to some additional required steps. As it stands now, your categories are tracked by Context A while your news is tracked by Context B-- You could detach/attach the category entities between the two contexts, but I'd say the recommended solution would be to change your repositories to accept a shared context through their constructors.
I'm assuming that you are instantiating the repositories in the controller's constructor, rather than using dependency injection, so you would modify your constructor code to do something like the following:
myContext = new YourContextClass();
catRepository = new CategoryRepository(myContext);
newsRepository = new NewsRepository(myContext);
You would then have to add the constructors to your repositories to assign the internal context property, and finally, adjust your controller to properly dispose of the context.
protected override void Dispose(bool disposing)
{
if (disposing)
myContext.Dispose();
base.Dispose(disposing);
}

NCommon 1.1 and EF4

I am new to NCommon and am looking for an example project to get started.
I am using EF4.
I assume one needs to use EF4 with POCOs?
Thanks for any help.
NCommon.Configure.Using(new StructureMapContainerAdapter(ObjectFactory.Container))
.ConfigureState<DefaultStateConfiguration>()
.ConfigureData<EFConfiguration>(config => config.WithObjectContext(
() =>
{
SiteContext db = new SiteContext(ConfigurationManager.ConnectionStrings["TestTheBest"].ConnectionString);
if (Transaction.Current != null )
{
db.Context.Connection.Open();
}
return db.Context;
}))
.ConfigureUnitOfWork<DefaultUnitOfWorkConfiguration>(config => config.AutoCompleteScope());
public class SiteContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Test> Tests { get; set; }
public DbSet<Client> Clients { get; set; }
public DbSet<Question> Questions { get; set; }
public DbSet<Section> Sections { get; set; }
public DbSet<Answer> Answers { get; set; }
public DbSet<GlobalSettings> GlobalSettings { get; set; }
public DbSet<PassageTest> PassageTest { get; set; }
public DbSet<PassageTestAnswer> PassageTestAnswer { get; set; }
public DbSet<SaaSUser> SaaSUser { get; set; }
public SiteContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
Context.SavingChanges += new EventHandler(Context_SavingChanges);
}
void Context_SavingChanges(object sender, EventArgs e)
{
if(Context.Connection.State==ConnectionState.Open)
Context.Connection.Close();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasMany(x => x.Invitations).WithRequired(x=>x.user).WillCascadeOnDelete(true);
modelBuilder.Entity<User>().HasMany(x => x.PassageTests).WithRequired(x => x.user).WillCascadeOnDelete(true);
modelBuilder.Entity<PassageTest>().HasMany(x => x.PassageTestAnswers).WithRequired(x => x.passageTest).WillCascadeOnDelete(true);
// modelBuilder.Entity<Company>().HasMany(x => x.Users).WithRequired(x => x.company).WillCascadeOnDelete(true);
modelBuilder.Entity<Question>().HasMany(x => x.Answers).WithRequired(x => x.question).WillCascadeOnDelete(true);
modelBuilder.Entity<Question>().HasMany(x => x.PassageTestAnswers).WithRequired(x => x.question).WillCascadeOnDelete(true);
modelBuilder.Entity<Test>().HasMany(x => x.Invitations).WithRequired(x => x.test).WillCascadeOnDelete(true);
modelBuilder.Entity<Test>().HasMany(x => x.PassageTests).WithRequired(x => x.test).WillCascadeOnDelete(true);
modelBuilder.Entity<Test>().HasMany(x => x.Sections).WithRequired(x => x.test).WillCascadeOnDelete(true);
modelBuilder.Entity<Client>().HasMany(x => x.Tests).WithRequired(x => x.client).WillCascadeOnDelete(true);
}
public ObjectContext Context
{
get { return ((IObjectContextAdapter)this).ObjectContext; }
}
}

Resources