I have 2 classes Entity and Instance. Instance class has an Entity object and a list of Attributes like this:
public class Instance
{
public Instance()
{
AttributeList = new ObservableCollection<AttributeClass>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Attributes
{
get => _attributes;
set
{
_attributes = value;
JsonConvert.PopulateObject(Attributes, AttributeList);
}
}
public Entity Entity
{
get => _entity ?? (_entity = new Entity());
set
{
_entity = value;
for (int i = _attributeList.Count - 1; i >= 0; i--)
{
_attributeList.RemoveAt(i);
}
foreach (Entity.AttributesDescribeClass attributeDescribe in _entity.Attributes)
{
_attributeList.Add(new AttributeClass() { AttributesDescribe = attributeDescribe });
}
}
}
public ObservableCollection<AttributeClass> AttributeList
{
get
{
return _attributeList;
}
set
{
_attributeList = value;
_attributes=JsonConvert.SerializeObject(AttributeList);
}
}
public class AttributeClass
{
[JsonIgnore]
public Entity.AttributesDescribeClass AttributesDescribe { get; set; }
public string Name
{
get => AttributesDescribe.Name;
}
public object Value { get; set; }
[JsonIgnore]
public ObservableCollection<InstanceValidator> Validators { get; set; }
public AttributeClass()
{
Validators = new ObservableCollection<InstanceValidator>();
}
}
}
The only this class can work is Entity is always set first, so that it will create the AttributeList, after that, we set Attributes and Populate AttributeList object. But it seems Attributes always set before Entity so this class can't work. Any way to indicate Dapper.NET to set Entity before Attributes?
Dapper processes columns from a reader, left-to-right. So: "whichever field comes back from the database first".
Related
I have two classes defined in my solution
public class Registration {
[...]
public list<Account> Accounts {get; set;}
}
public class Account {
[...]
public string Code { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
In the web service that I am consuming, the following class definitions are available
public partial class VendReg {
[...]
private Payment_Details[] requestDetailsField;
[System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)]
public Payment_Details[] RequestDetails {
get {
return this.requestDetailsField;
}
set {
this.requestDetailsField = value;
}
}
}
public partial class Payment_Details {
private string bk_CodeField;
private string bk_NameField;
private string bk_AddressField;
public string Bk_Code {
get {
return this.bk_CodeField;
}
set {
this.bk_CodeField = value;
}
}
public string Bk_Name {
get {
return this.bk_NameField;
}
set {
this.bk_NameField = value;
}
}
public string Bk_Address {
get {
return this.bk_AddressField;
}
set {
this.bk_AddressField = value;
}
}
}
I want to assign Account to Request Details which is an array of Payment_Details. I tried this code below
vendReg.RequestDetails = registration.Accounts.Cast<Payment_Details>().ToArray();
I got invalid cast exception: Unable to cast object of type 'Account' to type 'Payment_Details'
Please guide on what I am not doing right
You need to convert this yourself (or you can look into things like Automapper)
vendReg.RequestDetails = registration.Accounts.Select(acc =>
new Payment_Details {
Bk_Code = acc.Code,
Bk_Name = acc.Name,
Bk_Address = acc.Address
}).ToArray();
I'm new to Entity Framework. I was trying to get my data from my local database through this basic line of code, I wanted to store all of the objects in the "Object" row into a list.
But it seems like it doesn't work, whatever I try. I'm running SQL server, ASP.NET MVC. My code is something like these:
[HttpGet]
public List<Object> Function1()
{
List<Object> result = new List<Object>();
using (DatabaseContext db = new DatabaseContext())
{
result = db.Object.ToList();
// ...
return result;
}
}
It always ended up with "Specified cast is not valid." error:
This is where the error was caught:
Line 137: result = db.Object.ToList();
This is my model class, I added some functions though, but I haven't changed any default properties that Entity set up for me :
public partial class Object
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int Like { get; set; }
public int View { get; set; }
public byte Level
{
get { return Level; }
set
{
if (value < 1 || value > 3)
{
Level = 1;
throw new Exception("Level must be in 1 to 3. By default, it becomes 1");
}
else
{
Level = value;
}
}
}
public string Introduction { get; set; }
public string VideoUrl { get; set; }
public string Tag { get; set; }
public string Steps { get; set; }
public DateTime Date { get; set; }
public Object(string name, byte level, string introduction = null)
{
this.Name = name;
this.Level = level;
this.Introduction = introduction;
}
}
Is it oke to add functions and fix the properties like that ??
This is my table design in sql : pic
You have used public byte Level auto-property with a custom setter method.
This should be accompanied with a private backing variable. Something like
private byte _level
public byte Level
{
get { return _level; }
set
{
if (value < 1 || value > 3)
{
_level = 1;
throw new Exception("Level must be in 1 to 3. By default, it becomes 1");
}
else
{
_level = value;
}
}
}
You need to case the Object into a specific Model object something like this
[HttpGet]
public List<Object> Function1()
{
List<Object> result = new List<Object>();
using (DatabaseContext db = new DatabaseContext())
{
//result = db.Object;
result = (from d in db.Object.ToList()
select new Object{
prop1 = d.prop1,
prop2 = d.prop2,
.......
}).ToList();
// ...
return result;
}
}
How can I access the custom attribute of the parent or owner object.
Look at the FieldInfo property of the SQLFieldInfo struct
Here's a more detailed program that will compile and run that shows what I need.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Employee myclass = new Employee();
// Load from sql server...
myclass.Name = "Alain";
myclass.Age = 51;
//----
MessageBox.Show(myclass.Name.ToString()); // Should return Alain
MessageBox.Show(myclass.Age.FieldInfo.Type.ToString()); // Should output "int"
}
}
// This next class is generated by a helper exe that reads SQL table design and create the class from it
[SQLTableAttribute(DatabaseName = "Employees", Schema = "dbo", TableName = "Employees")]
public class Employee
{
[SQLFieldAttribute(FieldName = "ID", Type = SqlDbType.Int)]
public SQLFieldInfo<int> ID { get; set; }
[SQLFieldAttribute(FieldName = "Name", Type = SqlDbType.NVarChar, Size = 200)]
public SQLFieldInfo<String> Name { get; set; }
[SQLFieldAttribute(FieldName = "Age", Type = SqlDbType.Int)]
public SQLFieldInfo<int> Age { get; set; }
}
public struct SQLFieldInfo<T>
{
private readonly T value;
public SQLFieldInfo(T Value)
{
this.value = Value;
}
public static implicit operator SQLFieldInfo<T>(T Value)
{
return new SQLFieldInfo<T>(Value);
}
public T Value
{
get
{
return this.value;
}
}
public override string ToString()
{
return this.value.ToString();
}
public SQLFieldAttribute FieldInfo
{
get
{
// Need to retreive the attribute class of the parent or declaring member
return null;
}
}
}
// Holds the sql field information
public class SQLFieldAttribute : Attribute
{
public string FieldName { get; set; }
public SqlDbType Type { get; set; }
public bool AllowNull { get; set; }
public int Size { get; set; }
}
// Holds the sql table information
public class SQLTableAttribute : Attribute
{
public string DatabaseName { get; set; }
public string Schema { get; set; } = "dbo";
public string TableName { get; set; }
}
Thank you!
Alain
My data class is as follows (should be fairly translatable to A above):
public class Foo
{
[Argument(Help = "Name", AssignmentDelimiter = "=")]
public string Name
{
get;
set;
}
}
A helper class is responsible of reading attribute values of objects:
static public string GetCommandLineDelimiter<T>(Expression<Func<T>> property)
{
if(property != null)
{
var memberExpression = (MemberExpression)property.Body;
string propertyName = memberExpression.Member.Name;
PropertyInfo prop = typeof(Arguments).GetProperty(propertyName);
if(prop != null)
{
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(ArgumentAttribute), true);
if(dbFieldAtts.Length > 0)
{
return ((ArgumentAttribute)dbFieldAtts[0]).AssignmentDelimiter;
}
}
}
return null;
}
To use it, simply:
string delimiter = GetCommandLineDelimiter(() => myObject.Name);
That will get the attribute value of AssignmentDelimiter on property Name, i.e. "=".
First, MSDN is your friend.
Then, if you want to get the attributes for ancestors just specify true in the inherit flag of the method:
var attribute = typeof(A).GetProperty("myprop").GetCustomAttributes(true)
.OfType<MycustomAttrib>().FirstOrDefault();
This works. I am doing a lazy initialization of a reference to the custom attribute by using reflection to look at all the properties of all the types.
public class MycustomAttribAttribute : Attribute
{
public MycustomAttribAttribute(string name)
{
this.Name=name;
}
public string Name { get; private set; }
}
class A
{
public A() { MyProp=new B(); }
[MycustomAttrib(name: "OK")]
public B MyProp { get; set; }
}
class B
{
private static Lazy<MycustomAttribAttribute> att = new Lazy<MycustomAttribAttribute>(() =>
{
var types = System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes;
foreach(var item in types)
{
foreach(var prop in item.DeclaredProperties)
{
var attr = prop.GetCustomAttributes(typeof(MycustomAttribAttribute), false);
if(attr.Length>0)
{
return attr[0] as MycustomAttribAttribute;
}
}
}
return null;
});
public string MyProp2
{
get
{
return att.Value.Name;
}
}
}
class Program
{
static void Main(string[] args)
{
// Finds the attribute reference and returns "OK"
string name = (new A()).MyProp.MyProp2;
// Uses the stored attribute reference to return "OK"
string name2 = (new A()).MyProp.MyProp2;
}
}
I've the MyTableItem class that maps a DynamoDB table.
I need to implements the GetMyTableItemsWithoutFinalStatus method that query the table by specific filters on nested property of a custom type, MyStatus.
The filter has to check if:
there's no status
status is not initialized
there's no "final" status in the status list
date is greater than today - daysFromNow
So my conditions in OR are:
StatusCount == 0
Status == null
Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0
Date > DateTime.UtcNow.AddDays(-daysFromNow)
Actually I need to get back all the items that has no status or no final status, because I've to update them.
How can I implement the condition on nested property of MyStatus object?
This is my code
[Serializable]
public class MyTableItem
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty]
public string Field1 { get; set; }
[DynamoDBProperty]
public string Field2 { get; set; }
[DynamoDBProperty]
[DynamoDBGlobalSecondaryIndexRangeKey]
public DateTime Date { get; set; }
// My complex object
[DynamoDBProperty(typeof(MyStatusConverter))]
public MyStatus Status { get; set; }
[DynamoDBProperty]
public int StatusCount { get { return Status.Count; } set { value = Status.Count; } }
}
[Serializable]
public class MyStatus : IList<MyState>
{
private readonly IList<MyState> stateList = new List<MyState>();
public PeppolDespatchAdviceState this[int index]
{
get { return stateList[index]; }
set { stateList.Insert(index, value); }
}
public int Count
{
get { return stateList.Count; }
}
public bool IsReadOnly
{
get { return stateList.IsReadOnly; }
}
// IList interface implementation...
}
[Serializable]
public class MyState
{
public string DocumentType { get; set; }
public string Status { get; set; }
public string SkipCause { get; set; }
public DateTime Date { get; set; }
}
public enum StatusEnum
{
DEFAULT,
CREATED,
DELIVERED,
UNDELIVERABLE,
RE_RECEIVED
}
#region Converter definition
public class MyStatusConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value)
{
// Implementation...
}
public object FromEntry(DynamoDBEntry entry)
{
// Implementation...
}
#endregion
public IList<MyTableItem> GetMyTableItemsWithoutFinalStatus(long id, int daysFromNow = 3)
{
try
{
List<MyTableItem> items = new List<MyTableItem>();
DynamoDBOperationConfig operationConfig = new DynamoDBOperationConfig();
operationConfig.OverrideTableName = "MyTableName";
operationConfig.IndexName = "MyIndex";
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition(MyTableItemTableAttributes.StatusCount, ScanOperator.Equal, 0));
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Status, ScanOperator.IsNull));
// Here I need to add a LINQ condition: Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0 )
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Date, ScanOperator.GreaterThan, DateTime.UtcNow.AddDays(-daysFromNow)));
operationConfig.QueryFilter = conditions;
operationConfig.ConditionalOperator = ConditionalOperatorValues.Or;
DynamoDBContext context = new DynamoDBContext(DynamoDBClient);
items = context.Query<MyTableItem>(id, operationConfig).ToList();
return items;
}
catch (Exception ex)
{
throw;
}
}
I am using Entity Framework Code First Approach. I have following code to insert data into PaymentComponent and Payment tables. The data getting inserted into PaymentComponent table is not proper. It has NULL values in two columns (for one record) even though the corresponding properties in the domain objects are not null. What need to be changed in order to make it working?
EDIT
When I added the following in NerdDinners class, I am getting following result - it has new unwanted columns
public DbSet<ClubCardPayment> ClubCardPayments { get; set; }
ORIGINAL CODE
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();
}
}
DOMAIN CODE
public abstract class PaymentComponent
{
public int PaymentComponentID { get; set; }
public abstract int MyValue { get; set; }
public abstract string MyType { get; set; }
public abstract int GetEffectiveValue();
}
public partial class GiftCouponPayment : PaymentComponent
{
private int couponValue;
private string myType;
public override int MyValue
{
get
{
return this.couponValue;
}
set
{
this.couponValue = value;
}
}
public override string MyType
{
get
{
return this.myType;
}
set
{
this.myType = value;
}
}
public override int GetEffectiveValue()
{
if (this.PaymentComponentID < 2000)
{
return 0;
}
return this.couponValue;
}
}
public partial class ClubCardPayment : PaymentComponent
{
private int cardValue;
private string myType;
public override int MyValue
{
get
{
return this.cardValue;
}
set
{
this.cardValue = value;
}
}
public override string MyType
{
get
{
return this.myType;
}
set
{
this.myType = value;
}
}
public override int GetEffectiveValue()
{
return this.cardValue;
}
}
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<Payment> Payments { get; set; }
}
REFERENCE:
When using entity framework code-first mapping property to separate table, moves foreign key field
Override Entity Framework Entity Property
EntityFramework how to Override properties
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
Implement MyType and MyValue directly in the base class. EF allows shared members to be implemented only in the base class. Members implemented in derived class use their own columns in the resulting table.
you haven't defined the ClubCardPayment dbset in the datacontext.
insert this and it should work
public DbSet<ClubCardPayment> ClubCardPayments { get; set; }
You need to define the 2 classes that are actually implements of the abstract class, that's the only way EF will know the different classes and how to read/update/write instances of them.
(No need to map the abstract class in EF!).
This doesn't contribute to your question, but just a hint from my side:
Why do you implement MyValue and MyType explcitly in your derived classes? You can just put it into the abstract class, if the implementation is always the same...