In my DTO classes, I have some properties wiyth simple getter/setter (get; set;) while some of the properties have more complex getters/setters (like evaluating the value by some other property/variable etc)
[Serializable]
public class MyClassDto
{
public virtual string Name { get; set; }
public virtual string Description { get { return Name; } set { Name = value; } }
....
}
In above example, I want to get property Name, but do not want to get Description
I am trying to use PropertyInfo to find properties which have get;set; as getter/setter but failed to do so.
My reason for a such development is; properties with simple get;set; have a property with the same name in my Entity classes, alongside with a column in the database table. My Entities also have some properties which do not have a related column on the database table. So getting the properties with simple getters/setters will give me the properties with related database columns.
Meanwhile, I am using NHibernate.
check if this meets your requirment.
var property = typeof(MyClassDto).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(t => t.CanRead && t.CanWrite);
foreach (var item in property)
{
string propertyName = item.Name;
bool CompilerGenerated = item.GetGetMethod()
.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Any();
//Description is not CompilerGeneratedAttribute so return false;
}
Related
I am using EF Core and I have a scenario where the user can create a custom field and then creates options for that custom fields.
public class CustomField : Entity<long>
{
[Required]
public string Name { get; private set; }
public bool IsRequired { get; private set; }
public List<CustomFieldOption> customFieldOptions;
public virtual IReadOnlyCollection<CustomFieldOption> CustomFieldOptions => customFieldOptions;
protected CustomField()
{
}
public CustomField(long id, string name, bool isRequired, List<CustomFieldOption> customFieldOptions)
{
Id = id;
Name = name;
IsRequired = isRequired;
this.customFieldOptions = customFieldOptions;
}
}
public class CustomFieldOption : Entity<long>
{
[Required]
[MaxLength(256)]
public string Text { get; private set; }
protected CustomFieldOption()
{
}
public CustomFieldOption(string text)
{
Text = text;
}
}
public class Client : Entity<long>
{
public Name Name { get; set; }
private List<ClientCustomFieldOptionValue> customFieldOptionValues { get; set; } = new List<ClientCustomFieldOptionValue>();
public IReadOnlyCollection<ClientCustomFieldOptionValue> CustomFieldOptionValues => customFieldOptionValues;
public Client(Name name)
{
}
public Result AddCustomFieldOptionValues(List<ClientCustomFieldOptionValue> values)
{
return Result.Success();
}
public Result RemoveCustomFieldOptionValues(List<ClientCustomFieldOptionValue> values)
{
return Result.Success();
}
}
public class ClientCustomFieldOptionValue
{
public CustomFieldOption CustomFieldOption { get; private set; }
protected CustomFieldOptionValue()
{
}
public ClientCustomFieldOptionValue(CustomFieldOption customFieldOption)
{
CustomFieldOption = customFieldOption;
}
}
CustomFieldOption seems to be a Value Object as the text it holds is something that doesn't need an Id. But then in terms of store persistency needs an Id to be stored in database on a different table where it can be queries by Id etc...
I am not sure if I shall add it as an Entity because ValueObjects do not have Id.
One other problem I have is validation. If it is an Entity how can I validate Text property. I know validation on constructor is a bad idea. If I validate it in the ApplicationLayer then wherever I create a new object I have to validate that is not empty and the length.
If I forget to add validation in one of the application services and pass null Text then I create an inconsistent state.
Update #1
A Client can select one or many options of a custom field. I suppose these needed to be stored on a separate table ClientCustomFieldOptionValue. In that case is this an entity or a valueobject? And what about CustomFieldOption. Does it become an Entity? I am quite confused when to use Entity or ValueObjects
Try not to think of persistency details while designing domain model.
According to your description, CustomFieldOption expresses an individual property with no business relations to any other structure, thus:
it should not hold a business identifier
it should encapsulate its own validations
Meaning it fits the concept of a value-object (validation inside ctor).
When it comes to persistency, your repository model should be capable of storing CustomFieldOption objects in a child table (with DB identifier) referencing the parent table (CustomField objects)
On the query side, repository should be capable of aggregating data from these two tables into a single CustomField entity.
(How exactly you implement such DB capabilities depends on the ORM you choose to work with, EF in your case)
Just one observation, if you will use Ef Core and the containing entity has a one to many relationship with the value objects, you will have this limitation:
Owned Entity types, Ef Core
Owned types need a primary key. If there are no good candidates properties on the .NET type, EF Core can try to create one. However, when owned types are defined through a collection, it isn't enough to just create a shadow property to act as both the foreign key into the owner and the primary key of the owned instance
If you are mapping your entities and value objects using DbContext, you usually define an owned entity type for a value object or use a record type.
For owned entities, this creates a column in your table like this: EntityName_ValueObject (i.e. Person_Address) but this works for a single value object not a collection when you don't know in advance the number of items in the collection.
It is correct that you should not concern with persistence when designing your domain, but is also correct to think that having a value object with an identity does not make sense.
Most important, you should be aware of this potential issue early on.
I am trying to come up with a neat solution for this problem to make it scalable. I've got a DataTable dt, which has its structure read from a database. I want to be able to correctly map this data into the correct fields using Entity Framework and allow the code to function even if columns are added or deleted.
using (Entities db = new Entities())
{
foreach (DataRow dr in dt.Rows)
{
var result = db.myTable.SingleOrDefault(e => e.Email == dr["Email"].ToString());
foreach (SourceToDestinationMapping s in mapping)
{
// want to do something like this
result[s.DestinationColumn] = dt[s.DestinationColumn];
// instead of this
result.Name = dt["Name"].ToString();
result.Address = dt["Address"].ToString();
// all field mappings
}
}
}
Is this something that is possible to do? Or do I need to make code changes every time a new column gets added/removed? If this isn't something that works then I can switch to doing something like this without Entity Framework.
Edit:
Example would be:
1, EmailAddress, Email, 1
public partial class SourceToDestinationMapping
{
public int MappingId { get; set; }
public string SourceColumn { get; set; }
public string DestinationColumn { get; set; }
public bool Active { get; set; }
}
Since Entity Framework works with objects you'd need to use reflection to get and set properties without knowing which properties you need to operate on, and it can get pretty complicated if you have many types that you need to handle. So basically examine the type of the object you're looking at, get its list of properties, and search for columns with the same name as the property (or some other convention you have) in the data table row. But again, you'll need to handle the type conversions, if the property is an int you need to get the cell value as an int etc.
I have an empty sql table which contains around 100 column headers (fields), using database first approach I have created a single class with all the 100 fields as properties. Now I want to select only 10 fields out of all the properties and insert some data to those fields, such that the existing table should have the inserted data for only those 10 columns and the remaining columns should be updated with NULL. For instance,
public class Product
{
public int UniqueID {get; set;}
public string ProductName {get; set;}
public string type {get; set;}
etc......
}
Now I want the table should be updated with only UniqueID and ProductName and all the remaining fields should have NULL.
I am thinking of using Dictionary<string,object>, to add all the selected properties to dictionary and pass it to the database table.
Please share some ideas on how to implement this scenario using Entity Framework.
If it is MVC and you want to add/edit a subset use a view model:
// this is a viewmodel intended for a particular view, for example AddProductSubset.chtml
public class AddProductSubsetViewModel
{
public int UniqueID {get; set;}
public string ProductName {get; set;}
// add other properties you will be updating from the entity model
// you can also add properties from other entities or things only needed by the view
}
[HttpGet]
public ActionResult AddProductSubset(AddProductSubsetViewModel vm)
{
var vm = new AddProductSubsetViewModel();
// fill in any default values before add/edit
return View(vm);
}
[HttpPost]
public ActionResult AddProductSubset(AddProductSubsetViewModel vm)
{
if (ModelState.IsValid)
{
// map your viewmodel to the entity model. See automapper.
var product = new Product
{
UniqueID = vm.UniqueID, // unless this is identity, then omit
ProductName = vm.ProductName,
otherfield = vm.otherfield,
...
// unmapped entity fields will be set to their default (null, etc)
}
context.Products.Add(product);
context.SaveChanges();
return RedirectToAction("Index")
}
return View(vm);
}
You can reflect and hydrate properties to an instance, then add I think. This should do it
public void ReflectIntoModel<T>(Dictionary<string, object> dic)
{
T m = (T)Activator.CreateInstance(typeof(T));
var prop = typeof(T).GetProperties();
foreach (var a in prop)
{
dynamic val;
if (dic.TryGetValue(a.Name, out val))
a.SetValue(m, val);
}
}
Just make sure you're careful with typing the value, and the fact that the field names are case sensitive
Is there a way with dapper-dot-net to use an attribute to specify column names that should be used and not the property name?
public class Code
{
public int Id { get; set; }
public string Type { get; set; }
// This is called code in the table.
public string Value { get; set; }
public string Description { get; set; }
}
I'd like to be able to name my properties whatever I choose. Our database has no consistent naming convention.
If not with dapper, are there any additional similar options?
You can also check out Dapper-Extensions.
Dapper Extensions is a small library that complements Dapper by adding
basic CRUD operations (Get, Insert, Update, Delete) for your POCOs.
It has an auto class mapper, where you can specify your custom field mappings. For example:
public class CodeCustomMapper : ClassMapper<Code>
{
public CodeCustomMapper()
{
base.Table("Codes");
Map(f => f.Id).Key(KeyType.Identity);
Map(f => f.Type).Column("Type");
Map(f => f.Value).Column("Code");
Map(f => f.Description).Column("Foo");
}
}
Then you just do:
using (SqlConnection cn = new SqlConnection(_connectionString))
{
cn.Open();
var code= new Code{ Type = "Foo", Value = "Bar" };
int id = cn.Insert(code);
cn.Close();
}
Keep in mind that you must keep your custom maps in the same assembly as your POCO classes. The library uses reflection to find custom maps and it only scans one assembly.
Update:
You can now use SetMappingAssemblies to register a list of assemblies to scan:
DapperExtensions.SetMappingAssemblies(new[] { typeof(MyCustomClassMapper).Assembly });
If you are using a select statement directly or in a procedure you can just alias the columns.
SELECT code as Value FROM yourTable
Another approach is to just manually map it with the dynamic result.
var codes = conn.Query<dynamic>(...sql and params here...)
.Select<dynamic,Code>(s=>new Code{Id = s.Id, Type = s.Type, Value = s.code, Description = s.Description});
Clearly this introduces type-safety scenarios because you are querying on dynamic. Also, you have to manually map columns which is a bummer.
However, I tend to like this approach because it's so darned transparent. You can cast if need be (as is the case with Enums), and basically just do whatever it is you need to do to go from the db recordset to your properties.
For selects, you can add constructors to your classes to perform the mapping.
The constructor parameter names must match the table columns.
Below is an example from the source. The table will be correctly mapped to the class.
Table:
CREATE TABLE #Users (Id int, Name varchar(20))
Class:
class UserWithConstructor
{
public UserWithConstructor(int id, string name)
{
Ident = id;
FullName = name;
}
public int Ident { get; set; }
public string FullName { get; set; }
}
I'm using Entity Framework 4.1 Code First. Is there a built-in way to get a list of what properties have changed since the entity was loaded from the database? I know code first detects that an object was changed, but is there a way to get exactly what properties have changed?
For scalar and complex properties you can use the following to extract the changed property names of an entity myEntity:
var entry = context.Entry(myEntity);
var namesOfChangedProperties = entry.CurrentValues.PropertyNames
.Where(p => entry.Property(p).IsModified);
A few things to note here:
CurrentValues.PropertyNames only contains scalar and complex properties, not navigation properties.
Complex properties means: Only the name of the complex property which is declared on the entity, not the actual individual properties of the complex type itself, for example: If you have this model...
[ComplexType]
public class Address
{
public string Country { get; set; }
public string City { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
... then, if myEntity is a Person, CurrentValues.PropertyNames would contain "Id", "Name" and "Address" but not "Address.Country" or "Address.City" (nor "Country" or "City").
If a complex property is marked as modified (.IsModified in the code above is true) then this means that either the reference (Person.Address in the example above) has changed, no matter if actually the property values (Country and City) inside of the complex type have changed or not. Or that any of the properties of the complex type has changed (Country or City has changed). I believe it's not possible to find out which one, because EF always sends an UPDATE command for all complex type properties to the database, even if only one property has changed and the other remained unchanged. I would conclude from this that EF doesn't track changes of individual complex type properties.