Use anonymous type in generic class - c#

I have the following class with an Add mapper
public class OrderMapper<T> {
public OrderMapper<T> Add<TKey>(Expression<Func<T, TKey>> expression, String name) {
}
}
which I use as follows:
OrderMapper<Post> mapper = new OrderMapper<Post>().Add(x => x.Created, "created");
The problem is that sometimes I have the following:
posts.SelectMany(x => x.Category, (Post, Category) => new { Post, Category });
Which returns a list of anonymous types:
var objects = new { Post post, Category category }
I am not sure how to create an OrderMapper of this type ...
I think maybe I need to change my class method to an extension like:
OrderMapper mapper = objects.Add(...).Add(...)
Could someone tell me the best way to do this?

You can use a Create method for the OrderMapper class :
public class OrderMapper
{
public static OrderMapper<T> CreateMapperFor<T>(IEnumerable<T> typeProvider)
{
return new OrderMapper<T>();
}
}
And, use it as such :
var objects = Enumerable.Repeat(new { /* ... */ }, 1);
var mapper = OrderMapper.CreateMapperFor(objects)
.Add(/*...*/)
.Add(/*...*/);

Related

A Generic method to remove items from a collection when the type is sure to have a particular property

Consider this code.
distinctBrandIds is a collection of type long
List<long> distinctBrandIds = new List<long>{ 1, 5, 4};
BrandYesNo is a Dictionary with BrandId as key
Dictionary<long, bool> BrandYesNo = new Dictionary<long, bool>();
BrandYesNo.Add(1, false);
BrandYesNo.Add(2, false);
BrandYesNo.Add(3, false);
SomeClass has BrandId property
public class SomeClass{
public int ItemId {get; set;}
public long BrandId {get; set;}
// other properties
}
Items from CollectionOfSomeClass are removed when BrandId equals BrandId key in BrandYesNo dictionary with the value of false
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(sc => sc.BrandId == v);
}
});
In other places, the same code repeats with other collections of types in place of CollectionOfSomeClass.
The common thing is that the type of which the other collection is made of also has BrandId. So the check is always on BrandId property.
To create a generic method there are suggestions to use reflection and on those lines I have this:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass, List<long> distinctBrandIds, object propertyToCheck) where T : class
{
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll((rd) => {
PropertyInfo pi = typeof(T).GetProperty("BrandId");
pi.GetValue(rd) == v;
});
}
});
}
The predicate is not correct.
How do I proceed with this?
Thanks in advance.
Accepted Answer
Initially that was not the case but I convinced the powers that be for CodeCaster's solution.
No need for reflection here, if you know and control the types that are to be processed by this method. Given you say
The common thing is that the type of which the other collection is made of also has BrandId. So the check is always on BrandId property.
Create an interface:
public interface IBrand
{
long BrandId { get; }
}
Apply that to the appropriate classes:
public class SomeClass : IBrand
{ ... }
And modify your constraint:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass, List<long> distinctBrandIds)
where T : IBrand
{
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(rd => rd.BrandId == v);
}
}
}
To illustrate my comment, the following code should work but will be slow:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass,
List<long> distinctBrandIds)
where T : class
{
PropertyInfo pi = typeof(T).GetProperty("BrandId");
distinctBrandIds.ForEach(v =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(rd => ((long)pi.GetValue(rd) == v));
}
});
}
Or use Equals.
Note that this code should only be used if you don't have access to the classes code or cannot modify it. If not the case, #CodeMaster's solution is much safer + faster.
Similarly to #vc 74s answer, you could use reflection but cache it using a dictionary:
// Stores functions that take objects with "BrandId" properties
// and returns the value of the "BrandId" property casted to long
private static readonly Dictionary<Type, Func<object, long>> _getBrandId = new();
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass,
List<long> distinctBrandIds)
where T : class
{
// Check if the function is already cached
if (!_getBrandId.TryGetValue(typeof(T), out var getBrandId))
{
// Create the lambda using an expression tree
var lambda = Expression.Lambda<Func<object, long>>(
Expression.Convert(
Expression.Property(
Expression.Parameter(typeof(object)),
"BrandId"),
typeof(long)),
target);
// Store it to the cache
getBrandId = _getBrandId[typeof(T)] = lambda.Compile();
}
distinctBrandIds.ForEach((v) =>
{
if (BrandYesNo[v]) continue;
CollectionOfSomeClass.RemoveAll(rd => getBrandId(rd) == v);
});
}

How can i select generic columns from a table but make sure my keycolumn is selected too?

I have a table in my database with a lot of columns. I want to have a class where i load columns specified in the constructor into a list. I dont want to load all columns because that takes too long. Additionaly i may want to apply functions on specific columns becuase some data needs to be sanitized. Later i want to be able to return rows from this list by a keycolumn that is fixed (no need to specify it in the constructor).
This is kinda what i want:
public class DataHolder<TType> where TType:class
{
private List<TType> _data;
public DataHolder(DataContext context,Expression<Func<MyTable, TType>> select)
{
_data = context.MyTable.Select(select).DoSanitation().ToList();
//do sanitation on a column if it is in _data here
}
public TType Get(int id)
{
return _data.Single(d => d.Id == id);
}
}
And then i want to use it kinda like this:
var datHolder = new DataHolder(context, x=> new{x.Column1,x.Column2});
var row= datHolder.Get(123);
And row should have the fields "Column1" and "Column2" and "Id".
So i tried it by using anonymous types but because anonymous types cant use interfaces i am not able to make sure the type has the field "Id". Also the whole sanitation thing doesnt make sense on a anonymous type.
I have the sense that i am doing something i should not do or am not seeing a simple solution. I also had a look into Ado.Net which seems like it solve my problems because i can assemble columns adhoc. But all my other code runs with ef core so i am not sure if i should proceed in that direction.
You can't do this with anonymous types, but with types, known at compile time, you can do something like this:
public interface IEntity
{
public int Id { get; }
}
public class DataHolder<TType>
where TType : class, IEntity
{
private static readonly Lazy<IEnumerable<PropertyInfo>> MyTableProperties = new Lazy<IEnumerable<PropertyInfo>>(() => GetPublicInstanceProperties<MyTable>());
private static readonly Lazy<Expression<Func<MyTable, TType>>> Selector = new Lazy<Expression<Func<MyTable, TType>>>(GetSelector);
private readonly IReadOnlyDictionary<int, TType> data;
public DataHolder(MyContext context, Action<TType> doSanitation)
{
var entities = context.MyTable
.Select(Selector.Value)
.ToList();
foreach (var entity in entities)
{
doSanitation(entity);
}
data = entities.ToDictionary(_ => _.Id);
}
public TType Get(int id) => data[id];
private static Expression<Func<MyTable, TType>> GetSelector()
{
var lambdaParameter = Expression.Parameter(typeof(MyTable));
var memberBindings = GetPublicInstanceProperties<TType>()
.Select(propertyInfo => Expression.Bind(propertyInfo, Expression.MakeMemberAccess(lambdaParameter, MyTableProperties.Value.FirstOrDefault(p => p.Name == propertyInfo.Name))));
var memberInit = Expression.MemberInit(Expression.New(typeof(TType)), memberBindings);
return Expression.Lambda<Func<MyTable, TType>>(memberInit, lambdaParameter);
}
private static IEnumerable<PropertyInfo> GetPublicInstanceProperties<T>() => typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
}
GetSelector method is just a simple mapper: it assigns property of TType object from the property of MyTable object with the same name.
Usage:
using (var context = new MyContext())
{
var dataHolder = new DataHolder<EntityA>(context, entity =>
{
// TODO:
});
var row = dataHolder.Get(1);
}
where EntityA is:
public class EntityA : IEntity
{
public int Id { get; set; }
public int A { get; set; }
}

How to reuse data mapping Expression as a compiled Expression?

I have this code in LinqPad:
void Main() {
var a = Product.Select( DDL.ToDDL).Take(1).Dump();
}
That successfully queries SQL for two table fields instead of all of them using this POCO class (not sure if the inner static makes the outer class static too):
public class DDL {
public static readonly Expression<Func<Product, DDL>> ToDDL =
o => new DDL {
id = o.identifier,
name = o.pbfeattext
};
public int id {get;set;}
public string name {get;set;}
}
So I'd like to write the first line of code this way:
var a = Product.Select(o => o.AsDDL()).Take(1).Dump();
I've tried writing this code:
public static class DDL3 {
public static DDL AsDDL (this Product p) {
return new DDL {
id = p.identifier,
name = p.pbfeattext
};
}
}
Which produces the same result, but it retrieves the entire Product record in SQL instead of just the two fields we need. I've also tried this code, but it requires doing var a = Product.AsDDL().Take(1).Dump();. I need it in the other form (o => o.AsDDL()). (I've even tried using a constructor function, but SQL doesn't understand the function in that form.)
public static class DDL3
{
public static DDL AsDDL (this Product p)
{
return new DDL {
id = p.identifier,
name = p.pbfeattext
};
}
}
How would one code the Linq Expression?
AutoMapper might be for you. see this: https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions
It requires to configure mapping once, but after that, you can reuse DTO mapping anytime.
Here's an example from it:
public List<OrderLineDTO> GetLinesForOrder(int orderId)
{
Mapper.CreateMap<OrderLine, OrderLineDTO>()
.ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name);
using (var context = new orderEntities())
{
return context.OrderLines.Where(ol => ol.OrderId == orderId)
.Project().To<OrderLineDTO>().ToList();
}
}
This is what worked for me. I define the Expression as above, then a compile on the Expression right below it. This is really a View Model taking a POCO and mapping it to itself. You can add attributes to the methods so that JSON.NET doesn't serialize them (assuming...) The reason for Map and ToMap is the first is used to project fields in Entity Framework for example, and the other is used on in-ram collections.
public class DDL {
public static readonly Expression<Func<Product, DDL>> Map =
o => new DDL {
id = o.identifier,
name = o.pbfeattext
};
public static readonly Func<Product, DDL> ToMap =
DDL.Map.Compile();
public int id {get;set;}
public string name {get;set;}
}

generic class for linq / lambda expression

C# Entity framework 4.0
I have a database with 10's of table with 2 common columns 'id' and 'modstamp'
to access modstamp in a table I have a function
protected internal override string GetModStampinChild(int sid)
{
DBContext sq = new DBContext();
return sq.xxxx.Where(s => s.id == sid)
.Select(s => s.modstamp).SingleOrDefault().ToModStampString();
}
where xxxx change for every table.
I am presently overriding this function for every table.
Is there a way to use some kind of generic "class" which I could use where "xxxx" would be any table?
First, you would need to have all of your Entities implement either an interface or an abstract class that contains both the ID and ModStamp properties in it, let's call it Stampable:
public abstract class Stampable
{
[Key]
public int ID { get; set; }
[Required]
public string ModStamp { get; set; }
}
At that point, all you need to do for your method is to have it implement generic typing:
protected internal override string GetModStampInChild<T>(int sid) where T : Stampable
{
using (var sq = new DbContext())
{
return sq.Set<T>.Where(s => s.id == sid)
.Select(s => s.modstamp)
.SingleOrDefault()
.ToModStampString();
}
}
If I understand you correctly, you need a property Set<T> of DbContext class:
First, create base class of all your entity classes with id and modstamp properties. Then:
protected internal override string GetModStampInChild<T>(int sid) where T : BaseEntity
{
using (var sq = new DbContext())
{
return sq.Set<T>.Where(s => s.id == sid)
.Select(s => s.modstamp)
.SingleOrDefault()
.ToModStampString();
}
}
But you must use code-first paradigm for this method.
Another option would be add a new Property to your entity class via the partial class feature of c#.
So the entity definition generated might look like this, note I have no idea what the actual DataType of your ModStamp column is:
public partial class Company
{
public int Id { get; set; }
public byte[] ModStamp { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string State { get; set; }
}
Note the ModStamp column that you want to convert.
Then add to the Partial.cs file that EF creates code like this, note I have no idea what you actually want to do with the ModStamp value:
public static class ModConverter
{
public static string ToModStampString(byte[] modStamp)
{
return BitConverter.ToString(modStamp);
}
}
public partial class Company
{
public string ModStampString
{
get
{
return ModConverter.ToModStampString(this.ModStamp);
}
}
}
You would then have to manually add a new ModStampString Get Property for every Entity with a ModStamp Column like I did for the Company Entity.
Here is a solution that uses the Set method on the DbContext and expression trees to dynamically query that object.
private Expression<Func<TArg, bool>> CreatePredicate<TArg, TPredicateField>(string fieldName, TPredicateField value)
{
ParameterExpression parameter = Expression.Parameter(typeof(TArg), "o");
MemberExpression memberExpression = Expression.Property(parameter, fieldName);
var condition = Expression.Equal(memberExpression, Expression.Constant(value));
var lambda = Expression.Lambda<Func<TArg, bool>>(condition, parameter);
return lambda;
}
private Expression<Func<TArg, TPredicateField>> CreateSelector<TArg, TPredicateField>(string fieldName)
{
ParameterExpression parameter = Expression.Parameter(typeof(TArg), "o");
Expression propertyExpr = Expression.Property(parameter, fieldName);
var lambda = Expression.Lambda<Func<TArg, TPredicateField>>(propertyExpr, parameter);
return lambda;
}
public TSelectorField GetModStamp<TEntity, TPredicateField, TSelectorField>(TPredicateField id) where TEntity : class
{
using (var ctx = new OnTheFlyEntities("Data Source=(local);Initial Catalog=AscensionBO;Integrated Security=True;MultipleActiveResultSets=True"))
{
var predicate = CreatePredicate<TEntity, TPredicateField>("Id", id);
var selector = CreateSelector<TEntity, TSelectorField>("ModStamp");
TSelectorField item = ctx.Set<TEntity>().Where(predicate).Select(selector).SingleOrDefault();
return item;
}
}
You can then call it like this:
GetModStamp<Entity2, int, string>(1)
If you were willing to just return the found entity, you could eliminate the TSelectorField and then grab the ModStamp from the item after it is retrieved. That will drop one of the expression tree methods and a generic input on the main method.
As someone else suggested, you could go the interface route and use that example, it will be much simpler.

Fluent interface building different concrete types

I need some suggestions on how to build a fluent interface acting as a Builder, responsible for returning different concrete types depending on the methods called.
Imagine that I need to create one of the following types using my ProductBuilder (fluently): Product, ServiceProduct, PackagedProduct (both derived from Product).
I'm thinking of using a fluent syntax like this (other suggestions are more than welcome):
To create a Product:
var product = new ProductBuilder()
.Create("Simple product")
.WithPrice(12.5)
To create a ServiceProduct
var product = new ProductBuilder()
.Create("Service product")
.WithPrice(12.5)
.AsServiceProduct()
.ServiceProductSpecificMethods...()
And PackagedProduct with a call to AsPackagedProduct() instead of AsServiceProduct() etc. You get the idea.
I haven't found a sample that shows best practices on this. Only samples where the final build returns the same type.
Any suggestions?
I see two options here.
If there are a finite number of products that are fixed, and not designed to be extended, then just create a Create method for each product:
var product = new ProductBuilder()
.CreateSimple()
.WithPrice(12.5);
var product = new ProductBuilder()
.CreateService()
.WithPrice(12.5)
.ServiceProductSpecificMethods...();
If you don't want (or can't have) ProductBuilder to know all of the types of products, then I would use generics:
public class Product {}
public class SimpleProduct : Product {}
public class ServiceProduct : Product {}
var product = new ProductBuilder<SimpleProduct>()
.WithPrice(12.5);
Here's a starting place for the design to follow:
public class Product
{
public decimal Price { get; set; }
}
public class SimpleProduct : Product { }
public class ServiceProduct : Product
{
public string Service { get; set; }
}
public class ProductBuilder<T> where T : Product, new()
{
private List<Action<T>> actions = new List<Action<T>>();
public T Build()
{
T product = new T();
foreach (var action in actions)
{
action(product);
}
return product;
}
public void Configure(Action<T> action)
{
actions.Add(action);
}
}
public static class ProductExtensions
{
public static ProductBuilder<T> WithPrice<T>(this ProductBuilder<T> builder, decimal price)
where T : Product
{
builder.Configure(product => product.Price = price);
return builder;
}
public static ProductBuilder<T> WithService<T>(this ProductBuilder<T> builder, string service)
where T : ServiceProduct
{
builder.Configure(product => product.Service = service);
return builder;
}
}
If I got you correctly I would use generics here so I can write something like:
var product = new ProductBuilder()
.Create<Serviceproduct>()
.WithPrice(12.5)
.ServiceProductSpecificMethods...()
You may also add Build method before calling specific service methods so it will actually create final product:
var product = new ProductBuilder()
.Create<Serviceproduct>()
.WithPrice(12.5)
.Build()
.ServiceProductSpecificMethods...()

Categories