I am trying to implement a hierarchical inheritance structure in Entity Framework, specifically for settings. For example, lets say we have user preferences:
public class StorePreference: Preference { }
public class UserPreference : Preference { }
public class Preference {
public string BackgroundColor { get; set; }
public ContactMethod ContactMethod { get; set; }
}
public enum ContactMethod {
SMS,
Email
}
I'd like it so that if I lookup the user's preferences. If the user doesn't exist or the property value is null, it looks up the parent (store) default preferences.
Ideally, i'd like it to work similar to abstract inheritance:
public class UserPreference : StorePreference {
private string _backgroundColor;
public string BackgroundColor {
get {
if (this._backgroundColor == null)
return base;
return this._backgroundColor;
}
set { this._backgroundColor = value; }
}
}
If I were to write this as a SQL query, it'd be a CROSS APPLY with a CASE statement:
SELECT
CASE WHEN User.BackgroundColor == null THEN Store.BackgroundColor ELSE User.BackgroundColor END BackgroundColor,
CASE WHEN User.ContactMethod == null THEN Store.ContactMethod ELSE User.ContactMethod END ContactMethod
FROM UserPreference User
CROSS APPLY StorePreference Store
WHERE UserPreference.UserId = #UserId
Is there a way I can achieve loading this in EF?
In your base class add default property values:
public class Preference {
public string BackgroundColor { get; set; } = "Red";
public ContactMethod ContactMethod { get; set; } = ContactMethod.SMS;
}
Something like this to set from database:
public class StorePreference : Preference { }
public class UserPreference : Preference { }
public class Preference {
public Preference() {
BackgroundColor = DefaultPreference.BackgroundColor;
ContactMethod = DefaultPreference.ContactMethod;
}
public string BackgroundColor { get; set; }
public ContactMethod ContactMethod { get; set; }
public DefaultPreference DefaultPreference { get; set; }
}
public class DefaultPreference {
public string BackgroundColor { get; set; }
public ContactMethod ContactMethod { get; set; }
}
As long as the properties are public, entity won't have a problem pulling the data from another table as the default. You would need to create a private field to hold the data if you used a setter:
public class ChildTable : EntityBase {
private string _someCategory;
[Key]
[Column(name: "CHILD_ID")]
public override int Id { get; protected set; }
[Column(name: "SOME_CATEGORY")]
public string SomeCategory {
get { return _someCategory; }
set { _someCategory = value ?? ParentTable.SomeCategory; }
}
[ForeignKey("ParentTable")]
[Column(name: "PARENT_ID")]
public int ParentTableId { get; set; }
public virtual ParentTable ParentTable { get; set; }
}
This is just an alternative to a constructor, if you need more control over the setter logic, otherwise Austin's answer would be simpler to implement
Related
I've created three interfaces - IUser, ICostCenter, IDepartment. IUser and IDepartment are properties of ICostCenter.
public interface ICostCenter
{
IDepartment Department { get; set; }
User.IUser CostCenterHead { get; set; }
}
The class implementing ICostCenter will be used in the DbContext for my db.
public class tblCostCenter : WorkingInterface.Interface.Organization.ICostCenter
{
public tblCostCenter()
{
this.ID = Guid.NewGuid().ToString();
}
public string ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
private WorkingInterface.Interface.User.IUser CostCenterHead { get; set; }
public string UserID { get; set; }
[ForeignKey("UserID")]
public Model.tblUser UserObject
{
get { return (Model.tblUser)this.CostCenterHead; }
set { this.CostCenterHead = value; }
}
private WorkingInterface.Interface.Organization.IDepartment Department { get; set; }
public string DepartmenID { get; set; }
[ForeignKey("DepartmenID")]
public Model.tblDepartment DepartmentObject
{
get { return (Model.tblDepartment)this.Department; }
set { this.Department = (Model.tblDepartment)value; }
}
}
I'm getting an error because I made the IUser and IDepartment properties private. How can I properly implement the interface? I want these properties to be hidden.
The interface is declared explicitly as public, that means that all the members declared in that interface MUST be public
So you need to declare both of these properties as public:
public WorkingInterface.Interface.User.IUser CostCenterHead { get; set; }
public WorkingInterface.Interface.Organization.IDepartment Department { get; set; }
NOTE: these have been declared as implicit implementations, so they are available to all contexts. If you want to hide them from general use, you can use explicit implementation.
Because you tried to use private accessibility, I assume you generally want to hide these properties from view, you can do this and still honor the interface contract by using explicit implementation syntax:
WorkingInterface.Interface.User.IUser ICostCenter.CostCenterHead { get; set; }
WorkingInterface.Interface.Organization.IDepartment ICostCenter.Department { get; set; }
They are still public but can only be accessed by first casting the object to the specific interface type explicitly.
tblCostCenter obj = new tblCostCenter();
...
// this wont work:
Console.WriteLine(obj.CostCenterHead);
// instead you will have to cast the object first
Console.WriteLine((obj as ICostCenter)).CostCenterHead);
// or if the local variable was an ICostCenter
ICostCenter costObj = obj;
Console.WriteLine(costObj.CostCenterHead);
...
// Pattern matching can also be helpful in these scenarios
if (obj is ICostCenter cc)
Console.WriteLine(cc.CostCenterHead);
If you want to use explicit declaration in your class you could try this:
WorkingInterface.Interface.User.IUser ICostCenter.CostCenterHead { get; set; }
public string UserID { get; set; }
[ForeignKey("UserID")]
public Model.tblUser UserObject
{
get { return ((ICostCenter)this).CostCenterHead as Model.tblUser; }
set { ((ICostCenter)this).CostCenterHead = value; }
}
WorkingInterface.Interface.Organization.IDepartment ICostCenter.Department { get; set; }
public string DepartmenID { get; set; }
[ForeignKey("DepartmenID")]
public Model.tblDepartment DepartmentObject
{
get { return ((ICostCenter)this).Department as Model.tblDepartment; }
set { ((ICostCenter)this).Department = value; }
}
this only works if:
Model.tblDepartment : IDepartment
Model.tblUser : User.IUser
I am invoking a method in my constructor like below.Is this the right way to do to set properties based on some validations.Please suggest.
public class Asset
{
public Asset(string id)
{
SetStorageId(id);
}
public string AssetId { get; set; }
public string UtilId { get; set; }
public string MappingId { get; set; }
public bool IsActive { get; set; }
private void SetStorageId(string id)
{
if (Regex.Match(id, "^[A-Z][a-zA-Z]*$").Success)
{
AssetId = id;
}
else
{
UtilId = id;
}
}
}
In my opinion your design should be like below,
You should abstract common items to base class and create specific class inheriting this,
and decide from client(consumer) which instance do you need and construct it
public class AssetBase
{
public string MappingId { get; set; }
public bool IsActive { get; set; }
}
public class Asset : AssetBase
{
public string AssetId { get; set; }
}
public class Util : AssetBase
{
public string UtilId { get; set; }
}
static void Main(string[] args)
{
string id = Console.ReadLine();
if (Regex.Match(id, "^[A-Z][a-zA-Z]*$").Success)
{
Asset asset = new Asset();
asset.AssetId = id;
}
else
{
Util util = new Util();
util.UtilId = id;
}
}
simply try this
public class Asset
{
private string id;
public string AssetId { get; set; }
public string UtilId { get; set; }
public string Id
{
set
{
if (Regex.Match(value, "^[A-Z][a-zA-Z]*$").Success)
{
this.id = value;
}
else
{
UtilId = value;
}
}
get
{
return id;
}
}
}
When you create a property in c#, a private variable is created for that property on compile time. When you try to set the Id property in the code above the Id you pass goes into the value keyword and you can perform your validations on the value keyword and set your property accordingly.
No need to complicate your code with set methods, constructors or deriving classes
or you can even use data annotations which is a more elegant way https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute.aspx#Properties
using System.ComponentModel.DataAnnotations;
public class Asset
{
[RegularExpression("^[A-Z][a-zA-Z]*$")]
public string Id { get; set; }
}
It's not wrong. It can possibly grow to be a little confusing. Maybe you can make it clearer by moving the bod of SetStorageId to the constructor. Perhaps there is no need to complicate with subclassing, relative to other code within the project.
I have this model class "UserProfile", it's the original UserProfile class of Membership with a few added properties and methods.
[Table("UserProfile")]
public class UserProfile
{
public UserProfile()
{
this.DictionaryFrom = "eng";
this.DictionaryTo = "hun";
this.trainingType = "normal";
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string DictionaryFrom { get; set; }
public string DictionaryTo { get; set; }
public string trainingType { get; set; }
public virtual ICollection<ForeignExpression> learnedexpressions { get ; set ; }
}
My problem is that upon registering a new user, the three fields in the constructor don't get the values assigned to them (so, there's a NULL in the database for each of them).
The user can set them by choosing values from a list, but I'd like to have a default value for all of them. What am I doing wrong?
Not being a C# aficionado, I'd do something like this... there's probably a "better" way of doing it.
private string myValue = "default value";
public string MyValue {
get { return myValue; }
set {
if (null != value) { myValue = value; }
}
}
I have the below code in my Application.
public class GeneralInfo
{
private string _id;
private string _name;
public string id
{
set
{
_id = value;
}
get
{
return _id;
}
}
public string name
{
set
{
_name = value;
}
get
{
return _name;
}
}
}
public class SecureInfo
{
private string _password;
public string password
{
set
{
_password = value;
}
get
{
return _password;
}
}
}
public class User
{
}
I need to apply multiple inheritance in the above code ie. the classes GeneralInfo,SecureInfo properties should be accessible in the user class.
I know using interface Multiple inheritance can be achieved. But i need to define the properties in the base class which is restricted in Interface.
How I can achieve this?
C# does not support multiple inheritance. However you can achieve this via multiple interfaces.
public interface ISecureInfo
{
}
public interface IGeneralInfo
{
}
public class UserClass : ISecureInfo, IGeneralInfo {
}
You probably better off encapsulating the data in the class rather than trying to use something to do multiple inheritance here. See this question for some arguments for this.
You can achieve this through interface based inheritance:
public interface IGeneralInfo
{
String Id { get; set; }
String Name { get; set; }
}
public interface ISecureInfo
String Password { get; set; }
}
public class User : IGeneralInfo, ISecureInfo
{
// Implementation of IGeneralInfo
public String Id { get; set; }
public String Name { get; set; }
// Implementation of ISecureInfo
public String Password { get; set; }
}
Or, going one step further, through composition:
public interface IGeneralInfo
{
String Id { get; set; }
String Name { get; set; }
}
public class GeneralInfo : IGeneralInfo
{
public String Id { get; set; }
public String Name { get; set; }
}
public interface ISecureInfo
String Password { get; set; }
}
public class SecureInfo : IGeneralInfo
{
public String Password { get; set; }
}
public class User : IGeneralInfo, ISecureInfo
{
private GeneralInfo generalInfo = new GeneralInfo();
private SecureInfo secureInfo = new SecureInfo();
public String Id {
get { return generalInfo.Id; }
set { generalInfo.Id = value; }
}
public String Name {
get { return generalInfo.Name; }
set { generalInfo.Name = value; }
}
public String Password {
get { return secureInfo.Password; }
set { secureInfo.Password = value; }
}
}
From your sample description, encapsulation might be what you might want to use:
public class Info{
GeneralInfo general;
SecureInfo secure;
...
}
You cannot do multiple inheritance in C# because it is not supported like C++. In C# you can use interfaces for it and implement method and properties. For sample, you could have a base class
public abstract class Entity
{
public string Name { get; set; }
}
You also could have some interfaces:
public interface IPrint
{
void Print();
}
public interface IGenerate
{
void Generate();
}
And use it like multiples inheritance (but it is not, it is just a single inheritance and interfaces)
public class User : Entity, IPrint, IGenerate
{
public void Print()
{
// some code
// here you could access Name property, because it is on base class Entity
}
public void Generate()
{
// some code
}
}
And you could instance it using the abstractions:
Entity e = new User();
IPrint p = new User();
IGenerate g = new User();
User u = new User();
If you need implementations, you could do a hiearachy inherits, for sample:
User inherit from Person that inherit from Entity.
public class Entity
{
public int Id { get; set; }
public void Method()
{
// some code
}
}
public class Person : Entity
{
public string Name { get; set; }
public void AnotherMethod()
{
// some code
}
}
public class User : Person
{
public string Password { get; set; }
public bool CheckUser(string name, string passworkd)
{
// some code
}
}
I think the best would be to seperate the implementation of the interfaces and the real class you have at the end.
What I mean is something like the Bridge Pattern.
Your class (that will implement several interfaces) will just deleagte the method calls to the real implementation, that you can have in a seperate place and only once.
You could also use an approach like this. You would get to the same point than if you would be using multiple inheritance. That way, you could inherit only Entity if you don't need the SecureInfo stuff (i.e. for books and other stuff). Still, I think composition would do better in this case as others say...
class User : SecuredEntity { }
abstract class SecuredEntity : Entity, ISecureInfo
{
public string Password { get; set; }
}
abstract class Entity : IGeneralInfo
{
public string ID { get; set; }
public string Name { get; set; }
}
interface IGeneralInfo
{
string ID { get; set; }
string Name { get; set; }
}
interface ISecureInfo
{
string Password { get; set; }
}
I'd like to add/remove a column from MetaTable. But table.Column is of type ReadOnlycollection<MetaColumn>.
How can I modify, add or remove a column from the table?
Thank you.
Have you tried ScaffoldColumn?
[MetadataType(typeof(FooMetadata))]
[TableGroupName("Foo")]
public partial class Foo
{
[ScaffoldColumn(true)]
public string MyNewColumnNotinDBTable
{
get
{
return "FooBar";
}
}
}
public class FooMetadata
{
[ScaffoldColumn(false)] // hide Id column
public object Id { get; set; }
public object Name { get; set; }
public object MyNewColumnNotinDBTable { get; set; }
}