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; }
}
Related
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 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
I am having troubles trying to figure out how to use the EF6 interceptors to set a value on Insert/Update.
What I wanted to do is to have an interceptor to automatically create a new instance of Audit like so:
public class FooContext : DbContext
{
public DbSet<Invoice> Invoices { get; set; }
public DbSet<Audit> Audits { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public string Name { get; set; }
public Audit AuditAndConcurrencyKey { get; set; }
}
public class InvoiceItem
{
public int Id { get; set; }
public Invoice Header { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
//For legacy reasons. I know this design is wrong :(
public Audit AuditAndConcurrencyKey { get; set; }
}
public class Audit
{
public int Id { get; set; }
public int InstanceId { get; set; }
public string Message { get; set; }
}
[Test]
public void WillCreateAudit()
{
using (var db = new FooContext())
{
var inv = new Invoice {Name = "Foo Invoice"};
var invLine = new InvoiceItem {Header = inv, Price = 1, Name = "Apple"};
db.Invoices.Add(inv);
db.SaveChanges();
//Inceptors should figure out that we are working with "Invoice" and "InvoiceLine"
//And automatically create an "Audit" instance
Assert.That(inv.AuditAndConcurrencyKey != null);
Assert.That(invLine.AuditAndConcurrencyKey != null);
Assert.That(inv.AuditAndConcurrencyKey == invLine.AuditAndConcurrencyKey)
}
}
The first thing I checked is this example for SoftDeleteInterceptor. I don't think this is what I want because it looks like at the point where we are already generating the expression tree, we are no longer aware of the type of object you are working with.
I checked this example as well, but again, it looks like we are injecting strings instead of setting object references.
Ideally I want something like this:
public class AuditInterceptor
{
public void Intercept(object obj)
{
if (!(obj is Invoice) && !(obj is InvoiceItem))
return; //not type we are looking for, by-pass
//Set the audit here
}
}
I have the following in my Api Controller:
[AcceptVerbs("POST")]
public Model.ViewModel.ContactSaveRequest DeleteMethod(Model.ViewModel.ContactSaveRequest methodsToDelete)
{
var contactMethodRepos = new Model.ContactMethodRepository();
foreach (var contactMethod in methodsToDelete)
{
contactMethodRepos.Delete(contactMethod);
return contactMethod;
}
}
This is my class defining a contact method
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("contactID")]
public int ContactID { get; set; }
[JsonProperty("typeOfContactMethodID")]
public int TypeOfContactMethodID { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("methodsToDelete")]
public IEnumerable<ContactMethod> methodsToDelete { get; set; }
ContactSaverequest class:
public class ContactSaveRequest
{
[JsonProperty("contact")]
public Contact Contact { get; set; }
[JsonProperty("contactMethods")]
public IEnumerable<ContactMethod> ContactMethods { get; set; }
}
I have an array which pushes methods into it to be deleted (methodsToDelete). I am trying to use the Delete method on the array but keep getting the issue that contactSaveRequest doesn't contain a definition for GetEnumerator.
It sounds like you just want to use:
foreach (var contactMethod in methodsToDelete.ContactMethods)
You can't iterate over a ContactSaveRequest, but you can iterate over the IEnumerable<ContactMethod> that is returned by the ContactMethods property.
Try to implement IEnumerable interface like this
public class ContactSaveRequest : IEnumerable
{
}
Let's say I have to entities a POCO entity named SalesOrders and a regular entity generated from a SQL database called SalesOrderLines. I would like to create an association from SalesOrders to SalesOrderLines as in the following code but I keep getting the exception below the code. Does anyone know if this is possible?
[DataServiceKey("SalesOrderNumber")]
public class SalesOrder
{
[Key]
public int SalesOrderNumber { get; set; }
public string StockCode { get; set; }
public string Description { get; set; }
[Include]
[Association("SalesOrder_SalesOrderLine", "SalesOrderNumber", "SalesOrderNumber")]
public IQueryable<SalesOrderLine> SalesOrderLines
{
get
{
SalesOrderLineEntities oSalesOrderLineEntities = new SalesOrderLineEntities();
var soLines = from line in oSalesOrderLineEntities.SalesOrderLines
where line.OrderNumber == SalesOrderNumber.ToString() &&
line.StockCode == StockCode
select line;
return soLines;
}
set
{
}
}
}
'The property 'SalesOrderLines' on type 'ServiceName.NameSpace.SalesOrder' is not a valid property. Properties whose types are collection of primitives or complex types are not supported.'
It turns out that all I needed to to do was add the [Key] attribute to the generated metadata class.
[MetadataTypeAttribute(typeof(SalesOrderLines.SalesOrderLinesMetadata))]
public partial class SalesOrderLines
{
internal sealed class SalesOrderLinesMetadata
{
private SalesOrderLinesMetadata()
{
}
public DateTime DateStamp { get; set; }
public string OrderNumber { get; set; }
[Key]
public int SalesOrderLineID { get; set; }
public string SerialNumber { get; set; }
public string StockCode { get; set; }
}
}