C# CodeFirst Enum EntityFramework - c#

I'm trying to use codefirstdatabase in my applicantion, but I'm nothing having success in mapping the enum in my application.
I'm receiving that error when I try to use it.
(6,10) : error 3032: Problem in mapping fragments starting at line 6:Condition member 'BasicAccount.AccountType' with a condition other than 'IsNull=False' is mapped. Either remove the condition on BasicAccount.AccountType or remove it from the mapping.
public class PersonalDate
{
public int id { get; set; }
public ICollection<BaseAccount> BaseAccounts{ get; set; }
public PersonalDate()
{ }
}
public class BasicAccount
{
public int id { get; set; }
public AccountType AccountType { get; set; }
public PersonalDate PersonalDate { get; set }
public BasicAccount()
{
}
}
public class CurrentAccount: BasicAccount
{
public CurrentAccount()
{
AccountType = AccountType.CurrentAccount;
}
}
public class SavingAccount: BasicAccount
{
public SavingAccount()
{
AccountType = AccountType.SavingAccount;
}
}
public class SalaryAccount: BasicAccount
{
public SalaryAccount()
{
AccountType = AccountType.SalaryAccount;
}
}
public enum AccountType: int
{
undefined= 0,
SavingAccount= 1,
CurrentAccount= 2,
SalaryAccount= 3
}
public class BancoContext : DbContext
{
public DbSet<DadoPessoa> DadosPessoas { get; set; }
public DbSet<ContaBase> ContaBases { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<BasicAccount>()
.HasRequired<PersonalDate>(x => x.PersonalDate);
modelBuilder.Entity<BasicAccount>()
.Map<BasicAccount>( x => x.Requires("AccountType").HasValue((int)AccountType.Undefined))
.Map<SavingAccount>(x => .Requires("AccountType").HasValue((int)AccountType.SavingAccount))
.Map<CurrentAccount>(x => x.Requires("AccountType").HasValue((int)AccountType.CurrentAccount))
.Map<SalaryAccount>(x => x.Requires("AccountType").HasValue((int)AccountType.SalaryAccount));
}

Related

Disable name convention for navigation property ef-core2.2

I trying to use a identity class inside of my domain object but when i want to create migration for create database the ef core 2.2 say me:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: 'Warehouse' cannot be used as a property on entity type 'Existence' because it is configured as a navigation.
my dbcontext is
public class WarehousesContext : BaseContext<WarehousesContext>
{
public WarehousesContext(DbContextOptions<WarehousesContext> options) : base(options)
{
}
public WarehousesContext() : base() { }
public DbSet<Warehouse> Warehouses { get; set; }
public DbSet<Existence> Existences { get; set; }
public DbSet<Entry> Entries { get; set; }
public DbSet<Exit> Exits { get; set; }
public DbSet<Transfer> Transfers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("Inventory");
modelBuilder.Entity<Warehouse>().ToTable("Warehouses");
modelBuilder.Entity<Warehouse>().HasKey(w => w.Id);
modelBuilder.Entity<Warehouse>().Property(w => w.Id).HasConversion(v => v.Id, v => new WarehouseId(v));
modelBuilder.Entity<Existence>().ToTable("Existences");
modelBuilder.Entity<Existence>().HasKey(e => e.Id);
modelBuilder.Entity<Existence>().Property(e => e.Id).HasConversion(v => v.Id, v => new ExistenceId(v));
modelBuilder.Entity<Existence>().OwnsOne(e => e.Warehouse);
modelBuilder.Entity<Existence>().OwnsOne(e => e.Product);
}
}
my existences class is
public class Existence
{
public ExistenceId Id { get; private set; }
public WarehouseId Warehouse { get; private set; }
public ProductId Product { get; private set; }
public decimal Quantity { get; private set; }
public string Batch { get; private set; }
private Existence() { }
public Existence(WarehouseId warehouse, ProductId product, decimal quantity, string batch)
{
Warehouse = warehouse;
Product = product;
Quantity = quantity;
Batch = batch;
}
internal void Add(decimal quantity)
{
Quantity += quantity;
}
internal void Subtract(decimal quantity)
{
Quantity -= quantity;
if (Quantity < 0)
throw new Exception();
}
and my warehouseId class
public class WarehouseId
{
public string Id { get; private set; }
public WarehouseId()
{
this.Id = Guid.NewGuid().ToString();
}
public WarehouseId(string id)
{
Id = id;
}
}
i think the problem are that i use the "entityId" pattern to name my identity class so i want to know if existe some way to tell ef core "don't try to use navigation property convection here"
Change your Existence class as below(you can add your methods accordingly)
public class Existence
{
public string Id { get; private set; }
[ForeignKey("Warehouse")]
public string WarehouseId { get; private set; }
public ProductId Product { get; private set; }
public decimal Quantity { get; private set; }
public string Batch { get; private set; }
public virtual Warehouse Warehouse{get;set;)
}
public class Warehouse
{
//your other Warehouse properties
//add below line, if one to one relation
public virtual Existence Existence{get; set;}
//or, add below line, if one to many relation
//public virtual IList<Existence> Existence{get; set;}
}
Remove below lines from OnModelCreating method,
modelBuilder.Entity<Existence>().OwnsOne(e => e.Warehouse);
modelBuilder.Entity<Existence>().OwnsOne(e => e.Product);
and you can refer below SO question to correct your identity generation.
How does Entity Framework generate a GUID for a primary key value?

EF 6 Code First - Schema is not valid type not available

I did some refactoring to a code base, and created an abstract class SlottedHardware that held some common properties that other classes should use.
However, I am now getting the error:
Schema specified is not valid. Errors: The relationship 'MyProject.Models.NetworkDevice_Slots' was not loaded because the type 'MyProject.Models.Models.NetworkDevice' is not available.
when trying to create the database by setting my DbContext ctor to Database.SetInitializer<MyDbContext>(new CreateDatabaseIfNotExists<MyDbContext>());
I have been at this for hours, and would really appreciate if someone can lend a helping hand. Here are some of the entity classes, as well as the Fluent API mapping:
public abstract class EntityBase
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
}
public abstract class SlottedHardware : EntityBase
{
public int MaxSlots { get; set; }
public virtual ICollection<Slot> Slots { get; set; }
}
public class Slot : EntityBase
{
public string SlotIdentifier { get; set; }
public List<Card> CompatibleCards { get; set; } = new List<Card>();
public State State { get; set; }
public virtual NetworkDevice NetworkDevice { get; set; }
}
public class NetworkDevice : SlottedHardware
{
public string Vendor { get; set; }
public string Model { get; set; }
public List<UnpublishedConfig> UnpublishedConfigs { get; set; }
public List<PublishedConfig> PublishedConfigs { get; set; }
public State State { get; set; }
/*** Constructors ***/
public NetworkDevice()
{
MaxSlots = 0;
Slots = new List<Slot>();
UnpublishedConfigs = new List<UnpublishedConfig>();
PublishedConfigs = new List<PublishedConfig>();
}
public NetworkDevice(string vendor, string model, int maxSlots) : this()
{
Vendor = vendor;
Model = model;
if(maxSlots > 0)
{
MaxSlots = maxSlots;
}
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// NetworkDevice entity
modelBuilder.Entity<NetworkDevice>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("NetworkDevices");
});
modelBuilder.Entity<NetworkDevice>().HasKey(t => t.Id);
modelBuilder.Entity<NetworkDevice>().
HasMany(t => t.Slots).
WithOptional(t => t.NetworkDevice);
modelBuilder.Entity<NetworkDevice>().
HasMany(t => t.PublishedConfigs).
WithMany();
modelBuilder.Entity<NetworkDevice>().
HasMany(t => t.UnpublishedConfigs).
WithMany();
modelBuilder.Entity<NetworkDevice>().Property(t => t.MaxSlots).IsRequired();
modelBuilder.Entity<NetworkDevice>().Property(t => t.Model).IsRequired();
// Slot entity
modelBuilder.Entity<Slot>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Slots");
});
modelBuilder.Entity<Slot>().HasKey(t => t.Id);
modelBuilder.Entity<Slot>().HasOptional(t => t.NetworkDevice).WithMany(x => x.Slots);
modelBuilder.Entity<Slot>().HasMany(t => t.CompatibleCards).WithMany(x => x.Slots);
modelBuilder.Entity<Slot>().Property(t => t.SlotIdentifier).IsRequired();
modelBuilder.Entity<Slot>().Ignore(t => t.Card);
}

Switch between configurations in AutoMapper

I have this situation:
// Core Business classes
public class Invoice
{
public Guid Id { get; protected set; }
public int Number { get; set; }
public IList<InvoiceItem> Items { get; protected set; }
}
public class InvoiceItem
{
public Guid Id { get; protected set; }
public string Product { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
// MVC Models
public class InvoiceModel
{
public Guid Id { get; set; }
public int Number { get; set; }
public IList<InvoiceItemModel> Items { get; set; }
}
public class InvoiceItemModel
{
public Guid Id { get; set; }
public string Product { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
The automapper configuration
public class MyProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Invoice, InvoiceModel>();
Mapper.CreateMap<InvoiceItem, InvoiceItemModel>();
}
}
Then when I want to pass a model to my view, for example to edit an Invoice object, I do:
...
var invoice = Repository.Get<Invoice>(id);
return View("Update", Mapper.Map<InvoiceModel>(invoice));
...
And then I can iterate the Items collection with InvoiceItemModels.
The issue is when I want to retrieve a bunch of Invoices, for example in an index.
...
var invoices = Repository.ListAll<Invoice>();
return View("Index", invoices.Select(Mapper.Map<InvoiceModel>).ToList());
...
I don't want the "Items" to be loaded. A better configuration for this case will be:
public class MyFlatProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Invoice, InvoiceModel>()
.ForMember(m => m.Items, opt => opt.Ignore());
Mapper.CreateMap<InvoiceItem, InvoiceItemModel>();
}
}
But I have no idea how to switch between "Profiles".
Is there a way to "pick" a particular configuration of mapping?
Unfortunately, you have to create separate Configuration objects, and create a separate MappingEngine for each.
First, declear a static class to hold the mappers
public static class MapperFactory
{
public static MappingEngine NormalMapper()
{
var normalConfig = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
normalConfig.CreateMap<Invoice, InvoiceModel>();
normalConfig.CreateMap<InvoiceItem, InvoiceItemModel>();
var normalMapper = new MappingEngine(normalConfig);
return normalMapper;
}
public static MappingEngine FlatMapper()
{
var flatConfig = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
flatConfig.CreateMap<Invoice, InvoiceModel>()
.ForMember(m => m.Items, opt => opt.Ignore());
flatConfig.CreateMap<InvoiceItem, InvoiceItemModel>();
var flatMapper = new MappingEngine(flatConfig);
return flatMapper;
}
}
Then you can call the MappingEngine to do the mapping (The syntax is the same as Mapper object).
return View("Update", MapperFactory.FlatMapper().Map<InvoiceModel>(invoice));
return View("Update", MapperFactory.NormalMapper().Map<InvoiceModel>(invoice));

Entity Framework: Split table into multiple tables

I have the following table [PaymentComponent] created using following EF code first approach (TPH inheritance). It works fine. I need to change the database design – need to store GiftCouponPayments in GiftCouponPayment table and ClubCardPayments in ClubCardPayment table. What change need to be done in C# code to get the required database structure?
CODE
public abstract class PaymentComponent
{
public int PaymentComponentID { get; set; }
public int MyValue { get; set; }
public string MyType { get; set; }
public abstract int GetEffectiveValue();
}
public partial class GiftCouponPayment : PaymentComponent
{
public override int GetEffectiveValue()
{
if (MyValue < 2000)
{
return 0;
}
return MyValue;
}
}
public partial class ClubCardPayment : PaymentComponent
{
public override int GetEffectiveValue()
{
return MyValue;
}
}
public partial class Payment
{
public int PaymentID { get; set; }
public List<PaymentComponent> PaymentComponents { get; set; }
public DateTime PayedTime { get; set; }
}
//System.Data.Entity.DbContext is from EntityFramework.dll
public class NerdDinners : System.Data.Entity.DbContext
{
public NerdDinners(string connString): base(connString)
{
}
protected override void OnModelCreating(DbModelBuilder modelbuilder)
{
modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<GiftCouponPayment> GiftCouponPayments { get; set; }
public DbSet<ClubCardPayment> ClubCardPayments { get; set; }
public DbSet<Payment> Payments { get; set; }
}
CLIENT
static void Main(string[] args)
{
string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
using (var db = new NerdDinners(connectionstring))
{
GiftCouponPayment giftCouponPayment = new GiftCouponPayment();
giftCouponPayment.MyValue=250;
giftCouponPayment.MyType = "GiftCouponPayment";
ClubCardPayment clubCardPayment = new ClubCardPayment();
clubCardPayment.MyValue = 5000;
clubCardPayment.MyType = "ClubCardPayment";
List<PaymentComponent> comps = new List<PaymentComponent>();
comps.Add(giftCouponPayment);
comps.Add(clubCardPayment);
var payment = new Payment { PaymentComponents = comps, PayedTime=DateTime.Now };
db.Payments.Add(payment);
int recordsAffected = db.SaveChanges();
}
}
REFERENCE:
How do I get Entity Framework 4.3 Code First to map a subclass using Table Per Type (TPT)?
http://weblogs.asp.net/manavi/archive/2011/04/24/associations-in-ef-4-1-code-first-part-4-table-splitting.aspx
http://www.robbagby.com/entity-framework/entity-framework-modeling-entity-splitting/
Entity Framework Mapping Scenarios - http://msdn.microsoft.com/en-us/library/cc716779.aspx
http://blogs.microsoft.co.il/blogs/gilf/archive/2009/03/06/entity-splitting-in-entity-framework.aspx
In your Context class in OnModelCreating:
modelBuilder.Entity<GiftCouponPayment>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("GiftCouponPayment");
});
modelBuilder.Entity<ClubCardPayment>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("ClubCardPayment");
});

Entity Framework 4.1 Code First approach to create many-to-many relation

I'm using the Silverlight 5 Beta SDK and the EntityFramework 4.1 in an Silverlight Application.
I'll try to create the two tables 'Author' and 'Book'. In SQL, there should be a third (join) table, which makes the many-to-many relation between Author and Book (one author could have written many books and a book could be written from many authors).
This is what I've got so far:
namespace CodeFirst.Models.Web
{
public class Author
{
public Author()
{
this.Books = new HashSet<Book>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Book> Books { get; set; }
}
public class Book
{
public Book()
{
this.Authors = new HashSet<Author>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Author> Authors { get; set; }
}
// Should I do something like that:
public class AuthorMapping : EntityTypeConfiguration<Author>
{
public AuthorMapping() : base()
{
//this.HasMany (g => g.Books)
// .WithMany(m => m.Authors)
// .Map (gm => gm.ToTable ("Author_Book")
// .MapLeftKey ("AuthorID")
// .MapRightKey("BookID"));
}
}
public class CodeFirstModelContext : DbContext
{
public CodeFirstModelContext() : base()
{
this.Database.Connection.ConnectionString = #".\MSSQLSERVER2008;Database=CodeFirst;Trusted_Connection=true;";
}
public DbSet<Author> Authors { get; set; }
public DbSet<Book> Books { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new AuthorMapping());
// tell Code First to ignore PluralizingTableName convention
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
[EnableClientAccess()]
public class CodeFirstDomainService : DomainService
{
public CodeFirstDomainService()
{
this.m_modelContext = new CodeFirstModelContext();
}
public IQueryable<Author> GetAuthors()
{
return this.m_modelContext.Authors;//.Include("Books");
}
public void InsertAuthor(Author Author)
{
this.m_modelContext.Insert(Author);
}
public void UpdateAuthor(Author Author)
{
this.m_modelContext.Update(Author, this.ChangeSet.GetOriginal(Author));
}
public void DeleteAuthor(Author Author)
{
this.m_modelContext.Delete(Author);
}
public IQueryable<Book> GetBooks()
{
return this.m_modelContext.Books;//.Include("Authors");
}
public void InsertBook(Book Author)
{
this.m_modelContext.Insert(Author);
}
public void UpdateBook(Book Author)
{
this.m_modelContext.Update(Author, this.ChangeSet.GetOriginal(Author));
}
public void DeleteBook(Book Author)
{
this.m_modelContext.Delete(Author);
}
protected override void Dispose(bool disposing)
{
if (disposing)
this.m_modelContext.Dispose();
base.Dispose(disposing);
}
protected override bool PersistChangeSet()
{
this.m_modelContext.SaveChanges();
return base.PersistChangeSet();
}
private CodeFirstModelContext m_modelContext;
}
}
The most obvious problem is, that the navigation properties (Books in Author and Authors in Book) aren't created from the code designer in my client project.
What do I need to do?
EDIT:
Okay, now I'm able to use only one of the NavigationProperties simultaneously. If I try to 'Include' both I'm getting the following error:
Association 'Author_Book' defined on entity type 'CodeFirst.Models.Web.Author' is invalid. It is a foreign key association but the property type is not a singleton.
This is my updated code:
public class Author
{
public Author()
{
this.Books = new Collection<Book>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ID { get; set; }
[MaxLength(32)]
[Required]
public string Name { get; set; }
[Association("Author_Book", "ID", "ID")]
[Include]
public Collection<Book> Books { get; set; }
}
public class Book
{
public Book()
{
this.Authors = new Collection<Author>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ID { get; set; }
[MaxLength(32)]
[Required]
public string Name { get; set; }
[Association("Author_Book", "ID", "ID")]
[Include]
public Collection<Author> Authors { get; set; }
}
public class AuthorMapping : EntityTypeConfiguration<Author>
{
public AuthorMapping() : base()
{
this.HasMany (g => g.Books)
.WithMany(m => m.Authors)
.Map (gm => gm.ToTable("Author_Book"));
}
}
public class BookMapping : EntityTypeConfiguration<Book>
{
public BookMapping() : base()
{
this.HasMany (m => m.Authors)
.WithMany(g => g.Books)
.Map (gm => gm.ToTable("Author_Book"));
}
}
It seems to me, that Entity Framework still isn't able to deal with many-to-many relations. At least, that's what the error message implies.
EDIT2:
I've changed my code after I've read this post on social.msdn:
public class Author
{
public Author()
{
this.Books = new Collection<Book>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ID { get; set; }
[MaxLength(32)]
[Required]
public string Name { get; set; }
[Association("Author_Book", "Book_ID", "Author_ID")]
[Include]
[ForeignKey("Book_ID")]
public Collection<Book> Books { get; set; }
public int Book_ID { get; set; }
}
public class Book
{
public Book()
{
this.Authors = new Collection<Author>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ID { get; set; }
[MaxLength(32)]
[Required]
public string Name { get; set; }
[Association("Author_Book", "Author_ID", "Book_ID")]
[Include]
[ForeignKey("Author_ID")]
public Collection<Author> Authors { get; set; }
public int Author_ID { get; set; }
}
It doesn't fixed my problem. The same error is still present. I've tested to remove the AssociationAttribute without success. Am I doing somethinf wrong here?
I think problem here lies in the WCF RIA service, not anything EF related. That is, that WCF doesn't like interfaces. Solution would be use Collection instead of ICollection. I'm sure EF won't mind it and it will fix your WCF problem.
Edit: This may solve your problem http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/d894c8af-5985-4995-88e2-c8733e4a51ea

Categories