This is in reference to the question I asked regarding how to determine when items are added to the virtual ICollection property. As suggested, I have created a custom collection which inherits from Collection as shown below
public class EntityCollection<T> : Collection<T>
{
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
}
}
This is being used as
public class DbAppointment
{
public DbAppointment()
{
exceptionOcurrences = new EntityCollection<DbExceptionOcurrence>();
}
public virtual int AppointmentId { get; set; }
public virtual string Subject { get; set; }
public virtual string Body { get; set; }
public virtual DateTime Start { get; set; }
public virtual DateTime End { get; set; }
private ICollection<DbExceptionOcurrence> exceptionOcurrences;
public virtual ICollection<DbExceptionOcurrence> ExceptionOcurrences
{
get { return exceptionOcurrences; }
set { exceptionOcurrences = value; }
}
}
The problem is the only time the overridden InsertItem method seems to get called is if I initialise the database with a custom initialiser (example code below) and override the seed method!! What am I doing wrong?
Cheers
Abs
public class ContextInitializer : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
new List<DbAppointment>
{
new DbAppointment{ Subject = "hello", Body="world", Start=DateTime.Now, End=DateTime.Now.AddMinutes(30)},
}.ForEach(a => context.Appointments.Add(a));
new List<DbExceptionOcurrence>
{
new DbExceptionOcurrence{ExceptionDate=DateTime.Now}
}.ForEach(eo => context.ExceptionOcurrences.Add(eo));
base.Seed(context);
}
}
Related
I'm upgrading a netcore project from version 2.2 to 3.1. I've managed to make it build but on runtime I'm getting this error:
{"The child/dependent side could not be determined for the one-to-one relationship between 'RestaurantCustomQuestionCategory.QuizLimits' and 'CustomCategoryQuizLimits.RestaurantCustomCategory'. To identify the child/dependent side of the relationship, configure the foreign key property. If these navigations should not be part of the same relationship configure them without specifying the inverse. See http://go.microsoft.com/fwlink/?LinkId=724062 for more details."}
This is the code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RestaurantCustomQuestionCategory>()
.HasKey(t => new {t.RestaurantId, t.QuestionCategoryId});
}
RestaurantCustomQuestionCategory:
public class RestaurantCustomQuestionCategory : IQuizTimeLimitable
{
public RestaurantCustomQuestionCategory()
{
QuizLimits = new CustomCategoryQuizLimits(this);
}
public int QuestionCategoryId { get; set; }
[ForeignKey("QuestionCategoryId")]
public CustomCategory QuestionCategory { get; set; }
public int RestaurantId { get; set; }
[ForeignKey("RestaurantId")]
public Restaurant Restaurant { get; set; }
public CustomCategoryQuizLimits QuizLimits { get; set; }
public void UpdateQuizTimeLimit(CustomCategoryQuizLimits item)
{
this.QuizLimits = item;
}
public QuizLimitsBase GetQuizLimits()
{
return QuizLimits;
}
}
CustomCategoryQuizLimits:
public class CustomCategoryQuizLimits : QuizLimitsBase
{
public CustomCategoryQuizLimits(RestaurantCustomQuestionCategory restaurantCustomCategory)
{
RestaurantCustomCategory = restaurantCustomCategory;
}
public CustomCategoryQuizLimits()
{
}
public CustomCategoryQuizLimits(
RestaurantCustomQuestionCategory restaurantCustomCategory
, QuizQuestionsLimit limitsQuizQuestionsLimit
, QuizTimeLimit limitsQuizTimeLimit
) : base(limitsQuizQuestionsLimit, limitsQuizTimeLimit)
{
RestaurantCustomCategory = restaurantCustomCategory;
}
[Column("CustomCategoryId")]
public int QuestionCategoryId { get; set; }
[Column("CustomCategory_RestaurantId")]
public int RestaurantId { get; set; }
public RestaurantCustomQuestionCategory RestaurantCustomCategory { get; private set; }
public override QuizLimitsBase GetDefault()
{
return new CustomCategoryQuizLimits();
}
public override int GetChainId()
{
return RestaurantCustomCategory.Restaurant.ChainId;
}
public override IEnumerable<int> GetRestaurantIds()
{
return new List<int>() {RestaurantCustomCategory.RestaurantId};
}
}
I'm not sure what I have to change to fix this so I would love a bit of help.
I found a solution. It seems on the transitions to 3.0 EF gets confused with one to one relationships. So I added this on the Fluent:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RestaurantCustomQuestionCategory>()
.HasKey(t => new {t.RestaurantId, t.QuestionCategoryId});
modelBuilder.Entity<RestaurantCustomQuestionCategory>()
.HasOne(t => t.QuizLimits)
.WithOne(i => i.RestaurantCustomCategory)
.HasForeignKey<CustomCategoryQuizLimits>(t => new { t.RestaurantId, t.QuestionCategoryId });
}
Hi I am trying to build angular 2 web application using WebAPI, Entityframework that is loosely coupled using dependency injection. I am using unity for dependency injection. I have created multiple projects in one solution to address the separation concerns.
I have configured the dependency in unity.config however when i execute the webapi application and type the following url http://localhost:8702/api/allcustomers , I get message saying the customer controller doesn't have parameter-less constructor. I have set my break points in unity.config which never get hit
I would like to to understand if my implementation is correct as well
Below is the structure of my solution
CustomerOrder.Business.Objects
CustomerOrder.Data.Objects (references the business object)
CustomerOrder.Service.Api (references business object and service implementation)
CustomerOrder.Service.Implementation (references business objects and data objects)
CustomerOrder.Web (Yet to implement)
Below is the code
CustomerOrder.Business.Objects
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public int? Zip { get; set; }
}
CustomerOrder.Data.Objects
public class CustomerDao : ICustomerDao
{
IEnumerable<CustomerOrder.BusinessObjects.Customer> ICustomerDao.GetAllCustomers()
{
using (var customerOrderContext = new Entities())
{
return (from customer in customerOrderContext.Customers
select new CustomerOrder.BusinessObjects.Customer
{
Id = customer.Id,
FirstName = customer.FirstName,
LastName = customer.LastName,
Address = customer.Address,
City = customer.City,
Email = customer.Email,
Gender = customer.Gender,
State = customer.State,
Zip = customer.Zip
}).ToList();
}
}
}
public interface ICustomerDao
{
/// <summary>
/// Get All Customers
/// </summary>
/// <returns></returns>
IEnumerable<Customer> GetAllCustomers();
}
public interface IDaoFactory
{
ICustomerDao CustomerDao { get; }
}
}
public class DaoFactory : IDaoFactory
{
public DaoFactory(ICustomerDao CustomerDao, IProductDao ProductDao, IOrderDao OrderDao)
{
this.CustomerDao = CustomerDao;
}
public ICustomerDao CustomerDao { set; get; }
}
CustomerOrder.Service.Api
Unity.Config
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<ICustomerProvider, CustomerProvider>();
container.RegisterType<IOrderProvider, OrderProvider>();
container.RegisterType<IProductProvider, ProductProvider>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
CustomerController.cs
public class CustomerController : ApiController
{
private ICustomerProvider customerProvider;
public CustomerController(ICustomerProvider customerProvider)
{
this.customerProvider = customerProvider;
}
[Route("api/allcustomers")]
public IEnumerable<Customer> GetAllCustomers()
{
return customerProvider.GetAllCustomers();
}
CustomerOrder.Service.Implementation
public interface ICustomerProvider
{
IEnumerable<BusinessObjects.Customer> GetAllCustomers();
}
public class CustomerProvider : ICustomerProvider
{
private readonly IDaoFactory dataAccess;
public CustomerProvider(IDaoFactory dalFactory)
{
this.dataAccess = dalFactory;
}
public IEnumerable<BusinessObjects.Customer> GetAllCustomers()
{
IList<BusinessObjects.Customer> customerCollection = new List<BusinessObjects.Customer>();
dataAccess.CustomerDao.GetAllCustomers();
return customerCollection;
}
}
Context Class
namespace CustomerOrderData.EF
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class Entities : DbContext
{
public Entities()
: base("name=Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<OrderDetail> OrderDetails { get; set; }
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<Product> Products { get; set; }
}
}
In CustomerProvider, the IDaoFactory is probably not getting resolved because it's not registered. Add this to the Unity.Config:
container.RegisterType<IDaoFactory , DaoFactory >();
Please try including a parameterless constructor into the customer controller.
public CustomerController() {}
You should register not only IDaoFactory and his constructor dependencies
container.RegisterType<IDaoFactory, DaoFactory>();
container.RegisterType<ICustomerDao, CustomerDao>();
container.RegisterType<IOrderDao, OrderDao>();
container.RegisterType<IProductDao, ProductDao>();
I want to remove a row in database and insert it again with the same Id, It sounds ridiculous, but here is the scenario:
The domain classes are as follows:
public class SomeClass
{
public int SomeClassId { get; set; }
public string Name { get; set; }
public virtual Behavior Behavior { get; set; }
}
public abstract class Behavior
{
public int BehaviorId { get; set; }
}
public class BehaviorA : Behavior
{
public string BehaviorASpecific { get; set; }
}
public class BehaviorB : Behavior
{
public string BehaviorBSpecific { get; set; }
}
The entity context is
public class TestContext : DbContext
{
public DbSet<SomeClass> SomeClasses { get; set; }
public DbSet<Behavior> Behaviors { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<SomeClass>()
.HasOptional(s => s.Behavior)
.WithRequired()
.WillCascadeOnDelete(true);
}
}
Now this code can be executed to demonstrate the point
(described with comments in the code below)
using(TestContext db = new TestContext())
{
var someClass = new SomeClass() { Name = "A" };
someClass.Behavior = new BehaviorA() { BehaviorASpecific = "Behavior A" };
db.SomeClasses.Add(someClass);
// Here I have two classes with the state of added which make sense
var modifiedEntities = db.ChangeTracker.Entries()
.Where(entity => entity.State != System.Data.Entity.EntityState.Unchanged).ToList();
// They save with no problem
db.SaveChanges();
// Now I want to change the behavior and it causes entity to try to remove the behavior and add it again
someClass.Behavior = new BehaviorB() { BehaviorBSpecific = "Behavior B" };
// Here it can be seen that we have a behavior A with the state of deleted and
// behavior B with the state of added
modifiedEntities = db.ChangeTracker.Entries()
.Where(entity => entity.State != System.Data.Entity.EntityState.Unchanged).ToList();
// But in reality when entity sends the query to the database it replaces the
// remove and insert with an update query (this can be seen in the SQL Profiler)
// which causes the discrimenator to remain the same where it should change.
db.SaveChanges();
}
How to change this entity behavior so that delete and insert happens instead of the update?
A possible solution is to make the changes in 2 different steps: before someClass.Behavior = new BehaviorB() { BehaviorBSpecific = "Behavior B" }; insert
someClass.Behaviour = null;
db.SaveChanges();
The behaviour is related to the database model. BehaviourA and B in EF are related to the same EntityRecordInfo and has the same EntitySet (Behaviors).
You have the same behaviour also if you create 2 different DbSets on the context because the DB model remains the same.
EDIT
Another way to achieve a similar result of 1-1 relationship is using ComplexType. They works also with inheritance.
Here an example
public class TestContext : DbContext
{
public TestContext(DbConnection connection) : base(connection, true) { }
public DbSet<Friend> Friends { get; set; }
public DbSet<LessThanFriend> LessThanFriends { get; set; }
}
public class Friend
{
public Friend()
{Address = new FullAddress();}
public int Id { get; set; }
public string Name { get; set; }
public FullAddress Address { get; set; }
}
public class LessThanFriend
{
public LessThanFriend()
{Address = new CityAddress();}
public int Id { get; set; }
public string Name { get; set; }
public CityAddress Address { get; set; }
}
[ComplexType]
public class CityAddress
{
public string Cap { get; set; }
public string City { get; set; }
}
[ComplexType]
public class FullAddress : CityAddress
{
public string Street { get; set; }
}
please look at the code below.
class Program
{
static void Main(string[] args)
{
using (myContext context = new myContext())
{
Team t = new Team();
t.id = 1;
t.Name = "asd";
context.teamSet.Add(t);
context.SaveChanges();
}
}
}
public abstract class Base
{
public virtual int id { get; set; }
}
public abstract class Player : Base
{
public virtual string Name { get; set; }
public virtual int Number { get; set; }
public virtual Team team { get; set; }
[ForeignKey("team")]
public int teamId { get; set; }
}
public class Team : Base
{
public ICollection<Player> Players { get; set; }
public string Name { get; set; }
}
public class FootballPlayer : Player
{
public double Speed { get; set; }
}
public class BasketballPlayer : Player
{
public double Height { get; set; }
public double Speed { get; set; }
}
public class myContext : DbContext
{
public DbSet<Player> playerSet { get; set; }
public DbSet<Team> teamSet { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BaseConfiguration()).Add(new PlayerConfiguration()).Add(new TeamConfiguration()).Add(new FootballConfiguration()).Add(new BasketballConfiguration());
}
}
public class BaseConfiguration : EntityTypeConfiguration<Base>
{
public BaseConfiguration()
{
HasKey(k => k.id);
Property(p => p.id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
public class PlayerConfiguration : EntityTypeConfiguration<Player>
{
public PlayerConfiguration()
{
Map(p=>{
p.MapInheritedProperties();
p.ToTable("Player");
});
}
}
public class TeamConfiguration : EntityTypeConfiguration<Team>
{
public TeamConfiguration()
{
Map(p =>
{
p.MapInheritedProperties();
p.ToTable("Team");
});
}
}
public class FootballConfiguration : EntityTypeConfiguration<FootballPlayer>
{
public FootballConfiguration()
{
ToTable("FootballPlayer");
}
}
public class BasketballConfiguration : EntityTypeConfiguration<BasketballPlayer>
{
public BasketballConfiguration()
{
ToTable("BasketballPlayer");
}
}
My Player class and Team Class are derived from Based Class, and FootballPlayer and BasketballPlayer are derived from Player. But in the generated database, Player table doesn't contain a FK teamId, it is only a common property. Furthermore, the FootballPlayer and BasketballPlayer tables don't contains the properties which derived from Player class. Anyone can help?
What inheritance mapping are you trying to achieve? At the moment you have TPC between Base and Player and TPT between Player and its derived types. If you want to have inherited properties in those derived types you must use TPC as well but in such case there should be no Player table in your database. To use TPC for player you must use MapInheritedProperties in their mapping configurations.
1. I have created Test Class which contain Static Class and Property.
namespace QSys.Data.Domain.DataSecurity
{
public static class TestData
{
public static string MyName { get; set; }
}
}
2. Customer Model class and Custom Validation
namespace QSys.Data.Domain
{
[Serializable()]
public class Customer
{
[Key]
public virtual int Id { get; set; }
[CustomValidation(typeof(CustomerRequiredRules), "IsCompanyNameEmpty")]
public virtual string CompanyName { get; set; }
public virtual string City { get; set; }
}
public class CustomerRequiredRules
{
public static ValidationResult IsCompanyNameEmpty(string CompanyName, ValidationContext context)
{
if (TestData.MyName == "Imdadhusen")
{
return new ValidationResult("Company name not allowed!", new string[] { "CompanyName" });
}
return ValidationResult.Success;
}
}
}
3. Setting value of Static class like
public class AdminHomeViewModel
{
public AdminHomeViewModel()
{
TestData.MyName = "Imdadhusen";
}
}
4. I click on submit button, my custom validation getting fired and here i couldn't able to get value of TestData.MyName. it will display Null instead of Imdadhusen.
Any Answer, Suggestion or Comment highly appreciated!
Thanks,
Imdadhusen