Is it possible to have a foreign key mapping based on a specific column value.
I have the following entities.
public class Controller
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual List<ControllerDevice> ActiveDevices { get; set; }
public virtual List<ControllerDevice> TamperedDevices { get; set; }
public virtual List<ControllerDevice> IgnoredDevices { get; set; }
}
public class ControllerDevice
{
public int Id { get; set; }
public DeviceStatus Status { get; set; }
public int ControllerId { get; set; }
public int NetworkDeviceId { get; set; }
public virtual Controller Controller { get; set; }
public virtual NetowkDevice NetowkDevice { get; set; }
}
public class NetowkDevice
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public enum DeviceStatus
{
Active,
Tampered,
Ignored
}
Is it possible to have the ActiveDevices, TamperedDevices and IngoredDevices list be auto populated based on ControllerDevice DeviceStatus, or would I have to create three different tables for each list. IE ActiveControllerDevice, TamperedControllerDevices and IgnoredControllerDevices.
Please let me know if you require further explanation.
Use single devices collection:
public class Controller
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual List<ControllerDevice> Devices { get; set; }
}
...and filter it, when you need to process or display devices with specific Status value:
controller.Devices.Where(d => d.Status == DeviceStatus.Active);
Several tables for each devices status, and/or devices hierarchy (theoretically, you can solve this problem with a TPH inheritance) is a way to hell, because instead of single entity ControllerDevice with a status you'll get three entity types (ActiveControllerDevice, TamperedControllerDevice and IgnoredControllerDevice), which is not corresponding to model.
Instead of changing status, the device will change its type, and you cannot do that in simple way.
public class TestContext : DbContext
{
public TestContext()
{
Configuration.AutoDetectChangesEnabled = true;
Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = true;
Configuration.ValidateOnSaveEnabled = true;
}
public virtual DbSet<NetowkDevice> NetowkDevices{ get; set; }
public virtual DbSet<ControllerDevice> ControllerDevices{ get; set; }
public virtual DbSet<Controller> Controlleres{ get; set; }
}
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/d0443029-2175-4bde-a834-4f8dbf313201/
Should I enable or disable dynamic proxies with entity framework 4.1 and MVC3?
Yes, you can do that. Enum support was introduced in Entity Framework 5, .Net Framework 4.5. In Entity Framework, an enumeration can have the following underlying types: Byte, Int16, Int32, Int64 , or SByte.
And you can filter like this:
context.ControllerDevices.Where(d => d.Status == DeviceStatus.Active);
More here: http://msdn.microsoft.com/en-us/data/hh859576.aspx
Related
I'm trying to think of a way to store actual templates of ticket items in my Entity Framework MVC project. The thing is, I've already done a Code First migration process in the past. What I need to do is create logic in my code to allow someone to save time creating a ticket by using pre-loaded data from a template. My current inheritance model uses an abstract class (MasterTicket) which is used as the parent since to me there can be multiple categories (a Google Calendar based task, "Appointment Task" and a purely internal task, "General Task"). Here's my parent abstract class:
[Table("Ticket")]
[ModelBinder(typeof(MasterTicketBinder))]
public abstract class MasterTicket
{
[Key]
public Guid id{ get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ART { get; set; }
public DateTime openTime{ get; set; }
public DateTime? closeTime { get; set; }
private bool active = true;
public bool Active{ get => active; set => active = value; }
public string summary{ get; set; }
public string description{ get; set; }
public DateTime updateTime{ get; set; }
//TODO: Create foreign key relationship to user model
public Guid userUpdateId{ get; set; }
//TODO: Create foreign key relationship for tickets from other systems
public Guid externalAppId{ get; set; }
//TODO: Create foreign key relationship to user model
public Guid userOpenId{ get; set; }
public Guid? userCloseId { get; set; }
public Guid userOwnerId{ get; set; }
private int timesUpdated = 0;
public int TimesUpdated { get => timesUpdated; set => timesUpdated = value; }
public DateTime expectedCompletionTime{ get; set; }
public DateTime actualCompletionTime{ get; set; }
public List<MasterTicketItem> masterTicketItems{ get; set; }
public MasterTicket()
{
}
}
An here's an example of the concrete Google Calendar-based "Appointment Task" child:
[Table("AppointmentTickets")]
public class ApptTaskTicket : MasterTicket
{
public DateTime currentApptTime { get; set; }
public DateTime? endApptTime { get; set; }
public bool allDay { get; set; }
public string customerName { get; set; }
//TODO: Create foreign relationship
public Guid subjectPrsnlId { get; set; }
public string gCalEventId { get; set; }
public string customerPhone { get; set; }
public string customerEmail { get; set; }
public string preferredContactMethod { get; set; }
public List<ApptConfirmItem> apptConfirmItems { get; set; }
}
I know I can easily create a column for the MasterTicket class to indicate that it's a template, but to me I feel it's cleaner to have a separate "Template Table" if you will that will store pre-existing values that can be filled in with a form. In this case, I think I would WANT to create a duplicate class that would store said templates so that there are only several rows. What would be the best way to do this with Code First? Does someone feel I should take a different approach? Maybe DB First is a better way to go?
In case it matters, here's my DBContext for the Tickets:
// Code-Based Configuration and Dependency resolution
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class TicketDB : DbContext
{
public TicketDB(): base("AffirmativeServiceSystem.Properties.Settings.AffirmTaskManager")
{
}
public DbSet<MasterTicket> tickets { get; set; }
public DbSet<MasterTicketItem> ticketItems { get; set; }
}
My goal is to create the poco classes without knowing which ORM is going to be used.
Now observe the following code...
public class NeuralModel
{
public NeuralModel()
{
Configurations = new HashSet<NeuralModelConfiguration>();
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime? LastTrained { get; set; }
//Navigation properties
public ICollection<NeuralModelConfiguration> Configurations { get; set; }
//NotMapped properties
[NotMapped]
public NeuralModelConfiguration DefaultConfiguration { get { return Configurations.SingleOrDefault(config => config.IsDefault); } }
[NotMapped]
public bool IsTrained { get { return LastTrained.HasValue; } }
}
public class NeuralModelConfiguration
{
public NeuralModelConfiguration()
{
KeyValues = new HashSet<KeyValuePair<string, string>>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsDefault { get; set; }
public ICollection<KeyValuePair<string, string>> KeyValues
public int ModelId { get; set; }
//Navigation properties
public NeuralModel Model { get; set; }
}
Now suppose if I were to use Entity Framework Core, I get into the issue of mapping complex types (in my example it would be ICollection<KeyValuePair<string, string>>).
According to my research I came across two possible solutions:
Serialization
Another Entity
Now my question is that is there a third solution that do not require me to change my poco classes but rather do some sort of hidden processing at the dbcontext level?
Should there not be a third solution then out of the 2 available solutions which one would be considered better in terms of performance?
I am trying to create a composite key using two fields when using code first to existing fields in a table in a db;
[Key,Column("driverId", Order=0)]
[JsonProperty(PropertyName="driverid")]
public override int ID { get; set; }
[Key,Column("type", Order=1)]
[JsonProperty(PropertyName="typeid")]
public int Type { get; set; }
Now when I try to run a new migration i get the following error;
The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
DriversToVehicle_Driver_Target_DriversToVehicle_Driver_Source: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
The DriversToVehicle table is as follows;
public partial class DriversToVehicle
{
[Column("id"), Key]
public int ID { get; set; }
[Column("driverid")]
public int DriverID { get; set; }
[ForeignKey("DriverID")]
public Driver Driver { get; set; }
[Column("vehicleid")]
public int VehicleID { get; set; }
[ForeignKey("VehicleID")]
public Vehicle Vehicle { get; set; }
}
Extending this question, originally a single key on the ID, i.e.
[Column("driverId")]
[JsonProperty(PropertyName="driverid")]
public override int ID { get; set; }
Now moving forward, how will this effect the other entities linking to it (by this i mean code first in the classes)? will ef automatically sort this out? or do I now need to have both keys in other entities when linking to this class?
e.g. as before I would have had
public virtual Driver myDriver;
Obviously now instead of linking on the ID alone it needs to be linked with the Type as well.
Thanks in advance.
EDIT FOR ANSWER
Ok, I extracted the Type out to a seperate class. The main issue is now How do i mark the foreign key as also being a composite key?
I have the following classes
public partial class DriverType
{
[Column("Id")]
[JsonProperty(PropertyName = "drivertypeid")]
public override int ID { get; set; }
[JsonProperty(PropertyName = "drivertype")]
public string Name { get; set; }
}
Then in the Driver I have the following (reduced for brevity);
public partial class Driver : AuditableEntity<int>
{
[Key,Column("driverId", Order=0)]
[JsonProperty(PropertyName="driverid")]
public override int ID { get; set; }
[Key,Column("type", Order=1)]
[ForeignKey("DriverType")]
[JsonProperty(PropertyName="drivertypeid")]
public int DriverTypeId { get; set; }
public DriverType DriverType { get; set; }
How do I then add it to the DriverToVehicle class please? So far I have
public partial class DriversToVehicle
{
[Column("id"), Key]
public int ID { get; set; }
[Column("driverid", Order=0), ForeignKey("Driver")]
public int DriverID { get; set; }
public Driver Driver { get; set; }
[Column("type", Order = 1), ForeignKey("Driver")]
public int DriverTypeId { get; set; }
[ForeignKey("DriverTypeId")]
public DriverType DriverType { get; set; }
}
This doesnt look right to me though?
Since your Drivers table's Primary Key is now (DriverId, Type), you can no longer reference your drivers by DriverId alone - you must reference them by both DriverId and Type. Therefore, your DriversToVehicle table needs to look something like this:
public partial class DriversToVehicle
{
[Column("id"), Key]
public int ID { get; set; }
[Column("driverid")]
public int DriverID { get; set; }
[ForeignKey("DriverID")]
public Driver Driver { get; set; }
[Column("DriverType")]
public int DriverType { get; set; }
[ForeignKey("type")]
public int DriverType { get; set; }
[Column("vehicleid")]
public int VehicleID { get; set; }
[ForeignKey("VehicleID")]
public Vehicle Vehicle { get; set; }
}
However, as #hopeless states above, you may not need to model this join table if you correctly model your Driver and Vehicle types correctly.
HTH.
This has been puzzling me for quite some time but I keep getting an invalid identifier error when my entity framework tries to execute an oracle query. The classes in question are the following:
public class Projectship : ModelTrackingBase
{
[Column("PROJECTID")]
public long ProjectId { get; set; }
[Column("VISITID")]
public long VisitId { get; set; }
public virtual Bpid Bpid { get; set; } //new
public virtual Visit Visit { get; set; }
}
and
public class Bpid : EntityIdBase
{
[Column("BUDPRJID")]
[MaxLength(38)]
public string BPId { get; set; }
[Column("DESCRIPTION")]
[MaxLength(255)]
public string Description { get; set; }
[Column("CSTOBJ")]
[MaxLength(255)]
public string Custobj { get; set; }
[Column("PVID")]
[MaxLength(255)]
public string Pvid { get; set; }
public virtual ICollection<Projectship> Projectships { get; set; }
public IEnumerable<Visit> Visits
{
get { return Projectships.Select(p => p.Visit); }
}
[NotMapped]
public string DisplayName
{
get { return string.Format("{0}: {1}", BPId , Description); }
}
}
Now the EntityIdBase has the following:
public class EntityIdBase : EntityBase
{
[Column("ID")]
public long Id { get; set; }
}
It tries to keep on looking for a column Bpid_Id in the query. Does someone have any idea?
Bpid_id is created by EF because it can't automatically determine the relationship. Try adding the annotation:
[ForeignKey("ID")]
public virtual Bpid Bpid { get; set; } //new
You have specified a navigation property in the Projectship class
public virtual Bpid Bpid { get; set; }
You have not specified a foreign key to go with the navigation property so Entity Framework has chosen one, and it has chosen the name Bpid_Id. And it should be in the database. It should not be "non-existent".
You will probably find it easier to use Entity Framework if you add a foreign key like this:
public int BpidId { get; set; }
References:
Why does Entity Framework Reinsert Existing Objects into My Database?
Making Do with Absent Foreign Keys
Building my project using Code First EF.
I have a User class that has, as one of its properties, List<FriendGroup> (where a FriendGroup is basically just a collection of Users, kind of like 'Circles' in Google+). FriendGroup is defined in a different file as a POCO and... here's the thing... I never said anywhere that it is a ComplexType.
But when I try to run my application I get the exception,
System.InvalidOperationException: The type 'FriendGroup' has already been configured as an entity type. It cannot be reconfigured as a complex type.
I would be grateful for any insight anyone might be able to offer on why ASP.NET decided my class is a ComplexType. Thanks in advance!
ETA: relevant bits from my model:
namespace Clade.Models
{
public class User
{
[Key]
public int userID { get; private set; }
[Required]
public Profile profile { get; set; }
[Required]
public string userName { get; set; }
...
public List<FriendGroup> friendGroups { get; set; }
...
public List<AchievementEarned> achievementsEarned { get; set; }
}
}
namespace Clade.Models
{
public class FriendGroup
{
[Key]
[HiddenInput(DisplayValue = false)]
public int friendGroupID { get; private set; }
[HiddenInput(DisplayValue = false)]
public int userID { get; set; }
[Required]
public string friendGroupName { get; set; }
public Privacy defaultPrivacy { get; set; }
[Timestamp]
public DateTime dateCreated { get; set; }
public List<User> usersInFG { get; set; }
public void UpdateMe(FriendGroup editedFG)
{
friendGroupName = editedFG.friendGroupName;
defaultPrivacy = editedFG.defaultPrivacy;
usersInFG = editedFG.usersInFG;
}
}
}
There's also EF code, repositories, etc. but none of them know anything about the inner workings of any POCO. The only thing I see here that may be problematic is that User has a List<FriendGroup> and FriendGroup has a List<User>. But nothing has ever existed that annotated FriendGroup as a ComplexType.
ETA (2): Profile is also just a POCO:
namespace Clade.Models
{
public class Profile
{
[Key]
public int profileID { get; private set; }
public User user { get; set; }
public DiscussionGroup dg { get; set; }
public string location { get; set; }
public Privacy locationPrivacy { get; set; }
public string aboutMe { get; set; }
public Privacy aboutMePrivacy { get; set; }
...
}
}
User does have Lists of a couple of ComplexType-annotated objects, but EF did not complain about those.
namespace Clade.Models
{
[ComplexType]
public class AchievementEarned
{
public Achievement achievement { get; set; }
[Timestamp]
public DateTime dateEarned { get; set; }
}
}
ETA (3): Here's the method in UserRepository where the error occurs. It happens on the line which starts with var results.
public bool Add(User newUser)
{
bool rv = false;
//check to make sure no one else has the same username first
var results = from user in Users
where user.userName.Equals(newUser.userName)
select user;
if (results.Count() == 0)
{
this.context.Users.Add(newUser);
this.Commit();
rv = true;
}
return rv;
}
You may try the following:
Use int property instead of Enum
or try to update to EF 5 beta 2 with
PM> Install-Package EntityFramework -Pre
wich much better supports enums