Adding non table based DbSet causes error - ef-core-5.0

I have the following DbContext in a .net5 winforms EF XAF 21.2.5 standard security application created with the wizard and it runs OK.
[TypesInfoInitializer(typeof(DXApplication42ContextInitializer))]
public class DXApplication42EFCoreDbContext : DbContext {
public DXApplication42EFCoreDbContext(DbContextOptions<DXApplication42EFCoreDbContext> options) : base(options) {
}
public DbSet<ModuleInfo> ModulesInfo { get; set; }
public DbSet<ModelDifference> ModelDifferences { get; set; }
public DbSet<ModelDifferenceAspect> ModelDifferenceAspects { get; set; }
public DbSet<PermissionPolicyRole> Roles { get; set; }
public DbSet<DXApplication42.Module.BusinessObjects.ApplicationUser> Users { get; set; }
public DbSet<DXApplication42.Module.BusinessObjects.ApplicationUserLoginInfo> UserLoginInfos { get; set; }
public DbSet<ReportDataV2> ReportDataV2 { get; set; }
//public DbSet<DtoNum> TempNums { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<DXApplication42.Module.BusinessObjects.ApplicationUserLoginInfo>(b => {
b.HasIndex(nameof(DevExpress.ExpressApp.Security.ISecurityUserLoginInfo.LoginProviderName), nameof(DevExpress.ExpressApp.Security.ISecurityUserLoginInfo.ProviderUserKey)).IsUnique();
});
//modelBuilder.Entity<DtoNum>().HasNoKey();
}
}
public class DtoNum
{
public int Id { get; set; }
}
However if I uncomment the 2 commented lines I get an error
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=DevExpress.ExpressApp.EFCore.v21.2
StackTrace:
at DevExpress.ExpressApp.EFCore.EFCoreTypeInfoSource.SetupKeyMembers(TypeInfo typeInfo)
at DevExpress.ExpressApp.EFCore.EFCoreTypeInfoSource.RegisterEntity(Type type)
at DevExpress.ExpressApp.EFCore.TypeInfoSourceHelper.InitTypeInfoSource(EFCoreObjectSpaceProvider objectSpaceProvider)
at DevExpress.ExpressApp.EFCore.EFCoreObjectSpaceProvider..ctor(IDbContextFactory`1 dbContextFactory, ITypesInfo typesInfo)
at DevExpress.EntityFrameworkCore.Security.SecuredEFCoreObjectSpaceProvider..ctor(ISelectDataSecurityProvider selectDataSecurityProvider, IDbContextFactory`1 dbContextFactory, ITypesInfo typesInfo)
at DXApplication42.Win.DXApplication42WindowsFormsApplication.CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) in C:\Users\kirst\source\repos\DXApplication42\DXApplication42.Win\WinApplication.cs:line 34
Shown as
Looking inside EFCoreTypeInfoSources I see
private void SetupKeyMembers(TypeInfo typeInfo) {
IKey key = EntityTypes[typeInfo.FullName].FindPrimaryKey();
typeInfo.KeyMember = null;
foreach(IProperty property in key.Properties) {
typeInfo.AddKeyMember(typeInfo.FindMember(property.Name));
}
}
I want to use the non table based DbSet as explained here.
I posted the code to GitHub

I think the problem is that not all entities have a key so FindPrimaryKey would return null causing SetupKeyMembers to fail.

Related

FK for composite key splitted into 2 when table with certain name is added

So I have the following entities defined.
internal class DeliveryArea
{
public string Postcode { get; set; }
public string State { get; set; }
public string Country { get; set; }
public ICollection<DeliveryPrice> HasDeliveryPrices { get; set; }
}
internal class DeliveryPrice
{
public uint Id { get; set; }
public DeliveryArea ForDeliveryArea { get; set; }
public string DeliveryAreaPostcode { get; set; }
public string DeliveryAreaState { get; set; }
public string DeliveryAreaCountry { get; set; }
}
and my DbContext is as follow
internal class MyDbContext : DbContext
{
// DbSets.
public DbSet<DeliveryArea> DeliveryAreas { get; set; }
public DbSet<DeliveryPrice> DeliveryPrices { get; set; }
// Overrides.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(#"Data Source=Test.EFCore.db;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region DeliveryArea.
{
var entity = modelBuilder.Entity<DeliveryArea>();
// Setup case-insensitive columns.
entity.Property(i => i.Postcode).HasColumnType("TEXT COLLATE NOCASE");
entity.Property(i => i.State).HasColumnType("TEXT COLLATE NOCASE");
entity.Property(i => i.Country).HasColumnType("TEXT COLLATE NOCASE");
// Setup composite PK.
entity.HasKey(nameof(DeliveryArea.Postcode), nameof(DeliveryArea.State), nameof(DeliveryArea.Country));
}
#endregion
#region DeliveryPrice.
{
var entity = modelBuilder.Entity<DeliveryPrice>();
// DeliveryPrice x DeliveryArea | many-to-one
entity.HasOne(left => left.ForDeliveryArea)
.WithMany(right => right.HasDeliveryPrices)
.HasForeignKey(left => new { left.DeliveryAreaPostcode, left.DeliveryAreaState, left.DeliveryAreaCountry });
}
#endregion
}
}
When the database is generated, EF Core manage to generate appropriate FK that connects both table using the composite key. Everything looks fine and the diagram looks great.
Now, I added the following entity
internal class Currency
{
public uint Id { get; set; }
public ICollection<DeliveryPrice> ForDeliveryPrices { get; set; }
}
and updated DeliveryPrice class as follow
internal class DeliveryPrice
{
public uint Id { get; set; }
// Add the following
public Currency HasCurrency { get; set; }
public uint HasCurrencyId { get; set; }
public DeliveryArea ForDeliveryArea { get; set; }
public string DeliveryAreaPostcode { get; set; }
public string DeliveryAreaState { get; set; }
public string DeliveryAreaCountry { get; set; }
}
My DbContext is updated on top of existing, as follow
internal class MyDbContext : DbContext
{
// DbSets.
public DbSet<Currency> Currencies { get; set; }
// Existing codes remain...
// Overrides.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region Currency.
{
var entity = modelBuilder.Entity<Currency>();
// Currency x DeliveryPrice | one-to-many
entity.HasMany(left => left.ForDeliveryPrices)
.WithOne(right => right.HasCurrency)
.HasForeignKey(right => right.HasCurrencyId);
}
#endregion
// Existing codes remain...
}
}
When the new database is generated, the FK that connects both DeliveryArea and DeliveryPrice table is kinda splitted into 2, as follow
The funny thing is that when the Currencies table is renamed to, say Foo, the FK that connects both DeliveryArea and DeliveryPrice table looks OK.
UPDATE 01:
Normal looking FK
Here's a screenshot of the generated FK that splitted into 2
UPDATE 02:
Upon looking further into the issue, I've found that this is specific to DBeaver only. Viewing the same database file with other database viewer (e.g. DbSchema) does not have the issue.
Any idea what's going on?

How to fix ‘Cannot create a DbSet for 'DM_NCC_ThueSuat' because this type is not included in the model for the context’ error in C# ASP.NET

I have a code block regards get a list like that in aspnetzero:
public async Task<List<DMNCCThueSuatDto>> GetDSThueSuat()
{
using (_unitOfWorkManager.Current.SetTenantId(null))
{
var lstthueSuat = await _dmThueSuatRepository.Query(t => t.Where(i =>
i.IsDeleted == false)).OrderBy("thuesuat_ma asc").ToListAsync();
return ObjectMapper.Map<List<DMNCCThueSuatDto>>(lstthueSuat);
}
}
I expected a list of DMNCCThueSuatDto is returned but the error
Cannot create a DbSet for 'DM_NCC_ThueSuat' because this type is not
included in the model for the context.
is always displayed.
Also, i had myown a declaration
public virtual DbSet DS_ThueSuat { get; set; }
in my DBContext.
In my mariadb database, i had a table called "vs_dm_ncc_thuesuat"
and i have already declare a class for mapping to the table above
namespace VS.vHoaDon.Domains.DanhMuc.DMNhaCungCap
{
[Table("vs_dm_ncc_thuesuat")]
[MultiTenancySide(MultiTenancySides.Host)]
public class DM_NCC_ThueSuat : FullAuditedEntity
{
public int ThueSuat_Ma { get; set; }
public string ThueSuat_Ten { get; set; }
public int ThueSuat_GiaTri { get; set; }
public bool ThueSuat_HieuLuc { get; set; }
public DateTime? ThueSuat_BatDau { get; set; }
public DateTime? ThueSuat_KetThuc { get; set; }
}
}
I don't know why?
Any helps is appreciated.
Thank you so much.

EF7 (Code First) + SQLite doesn't create a database and the tables for the models

Im currently trying to recreate the example, done in the documentation http://ef.readthedocs.org/en/latest/getting-started/uwp.html , using EF7 and SQLite to create a Universal Windows Platform app.
I've installed the required EF7 and EF7 Commands package, and created the model and context:
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string dirPath = ApplicationData.Current.LocalFolder.Path;
string connectionString = "Filename=" + Path.Combine(dirPath, "blogging.db");
optionsBuilder.UseSqlite(connectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
My problem now is, that after building the solution, the command that should scaffold a migration to create the initial set of tables for my model fails with the following exception:
PM> Add-Migration MyFirstMigration
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.RuntimeAssembly.get_DefinedTypes()
at Microsoft.Data.Entity.Design.Internal.StartupInvoker..ctor(String startupAssemblyName, String environment)
at Microsoft.Data.Entity.Design.DbContextOperations..ctor(ILoggerProvider loggerProvider, String assemblyName, String startupAssemblyName, String environment)
at Microsoft.Data.Entity.Design.MigrationsOperations..ctor(ILoggerProvider loggerProvider, String assemblyName, String startupAssemblyName, String environment, String projectDir, String rootNamespace)
at Microsoft.Data.Entity.Design.OperationExecutor.<>c__DisplayClass3_0.<.ctor>b__3()
at Microsoft.Data.Entity.Internal.LazyRef`1.get_Value()
at Microsoft.Data.Entity.Design.OperationExecutor.<AddMigrationImpl>d__7.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Microsoft.Data.Entity.Design.OperationExecutor.OperationBase.<>c__DisplayClass4_0`1.<Execute>b__0()
at Microsoft.Data.Entity.Design.OperationExecutor.OperationBase.Execute(Action action)
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Does anyone have a solution for this problem ?
Thanks in advance
In my case the solution to the problem was to create the database and tables through code in the app.xaml, before the app starts.
using (var db = new BloggingContext())
{
db.Database.EnsureCreated();
db.Database.Migrate();
}
Context + Model:
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string path = ApplicationData.Current.LocalFolder.Path;
if (!File.Exists(Path.Combine(path, "blogging.db")))
{
File.Create(Path.Combine(path, "blogging.db"));
}
optionsBuilder.UseSqlite("Data Source=" + Path.Combine(path, "blogging.db")+";");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Make Blog.Url required
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
}
[Table("Blog")]
public class Blog
{
[Key]
public int BlogId { get; set; }
[MaxLength(100)]
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
[Table("Post")]
public class Post
{
[Key]
public int PostId { get; set; }
[MaxLength(30)]
public string Title { get; set; }
[MaxLength(250)]
public string Content { get; set; }
public int BlogId { get; set; }
[ForeignKey("BlogId")]
public Blog Blog { get; set; }
}
Additionally before accessing the database, i ensure that its created, e.g.
using (var db = new BloggingContext())
{
db.Database.EnsureCreated();
Blogs.ItemsSource = db.Blogs.ToList();
}

Using ComplexType with ToList causes InvalidOperationException

I have this model
namespace ProjectTimer.Models
{
public class TimerContext : DbContext
{
public TimerContext()
: base("DefaultConnection")
{
}
public DbSet<Project> Projects { get; set; }
public DbSet<ProjectTimeSpan> TimeSpans { get; set; }
}
public class DomainBase
{
[Key]
public int Id { get; set; }
}
public class Project : DomainBase
{
public UserProfile User { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IList<ProjectTimeSpan> TimeSpans { get; set; }
}
[ComplexType]
public class ProjectTimeSpan
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public bool Active { get; set; }
}
}
When I try to use this action I get the exception The type 'ProjectTimer.Models.ProjectTimeSpan' has already been configured as an entity type. It cannot be reconfigured as a complex type.
public ActionResult Index()
{
using (var db = new TimerContext())
{
return View(db.Projects.ToList);
}
}
The view is using the model #model IList<ProjectTimer.Models.Project>
Can any one shine some light as to why this would be happening?
Your IList<ProjectTimeSpan> property is not supported by EF. A complex type must always be part of another entity type, you cannot use a complex type by itself. If you absolutely need to have ProjectTimeSpan as a complex type, you will need to create a dummy entity type that only contains a key and a ProjectTimeSpan, and change the type of Project.TimeSpans to a list of that new type.

MVC3 Multiple Foreign Key Values

I have two simple model classes.
Service
Attendee
Each service can be attended by 1 or more people. I want Create and Edit views based on service where all attendees display as a check box and when any of the selected/unselected it should add or remove from the corresponding service in the database.
I have been trying to build it for more than a week now but no success!
any help will be highly appreciated.
My code is as follows for these classes.
public class Service
{
public int ServiceID { get; set; }
public string Problem { get; set; }
public virtual ICollection<Attendie> AttendedBy { get; set; }
}
public class Attendie
{
public int AttendieID { get; set; }
public string Name { get; set; }
public virtual Service Service { get; set; }
}
public class ServiceAttendiesDBContext: DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<Service> Services { get; set; }
public DbSet<Attendie> Attendies { get; set; }
}
public class ServiceAttendiesInitializer : DropCreateDatabaseAlways<ServiceAttendiesDBContext>
{
protected override void Seed(ServiceAttendiesDBContext context)
{
base.Seed(context);
var attendies = new List<Attendie>
{
new Attendie{AttendieID=1,Name="Attendie1"},
new Attendie{AttendieID=2,Name="Attendie2"},
new Attendie{AttendieID=3,Name="Attendie3"}
};
attendies.ForEach(at => context.Attendies.Add(at));
context.SaveChanges();
var services = new List<Service>
{
new Service{ ServiceID=1,Problem="Problem1",AttendedBy=new List<Attendie>()},
new Service{ ServiceID=2,Problem="Problem2",AttendedBy=new List<Attendie>()},
new Service{ ServiceID=3,Problem="Problem3",AttendedBy=new List<Attendie>()}
};
services.ForEach(ser => context.Services.Add(ser));
context.SaveChanges();
services[0].AttendedBy.Add(attendies[0]);
services[0].AttendedBy.Add(attendies[1]);
services[1].AttendedBy.Add(attendies[2]);
services[1].AttendedBy.Add(attendies[2]);
services[2].AttendedBy.Add(attendies[1]);
context.SaveChanges();
}

Resources