I want to store some collection properties in string column in database.
Some of them are IEnumerable<> and some are List<>
Using Ef core I've created such a extension method:
public static void StringWithStyleConversion<T>(this PropertyBuilder<T> builder)
where T : IEnumerable<StringWithStyle>
{
builder.HasConversion(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),
v => JsonSerializer.Deserialize<T>(v, (JsonSerializerOptions)null)
,
new ValueComparer<T>(
(arr1, arr2) => arr1.Count() == arr2.Count() && !arr1.Except(arr2).Any(),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => new List<StringWithStyle>(c))
);
}
But I get an error:
Cannot implicitly convert type System.Collections.Generic.List<TypiconOnline.Domain.ItemTypes.StringWithStyle>' to 'T'
on a line:
c => new List<StringWithStyle>(c))
Could you please help me, how can it be solved?
Sorry, I've already found an answer
c => (T) Convert.ChangeType(new List<StringWithStyle>(c)), typeof (T))
UPDATE
It doesn't work. Because List<StringWithStyle> doesn't implement IConvertible
Related
I'm trying to return an expression from a Select, so I have an expression returning an expression (I think - maybe it's a lambda returning an expression, I'm not sure of the terminology)
If I create a variable that explicitly gives a type to the expression then it works e.g.
housingDivisions.Select(id => {
Expression<Func<Document, bool>> expression = d => d.HousingDivisions.Any(h => h.HousingDivisionId == id);
return expression;
})
however this code seems equivalent (and less wordy)
housingDivisions.Select(id => d => d.HousingDivisions.Any(h => h.HousingDivisionId == id))
but causes a compile error:
Error CS0411 The type arguments for method 'Enumerable.Select(IEnumerable, Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Is there any way of getting this to compile without having to create an unnecessary variable?
The problem is both the type d and the delegate type of d => ... are both unknown and cannot be assumed from anywhere. You can solve both in one go by instantiating the delegate type:
housingDivisions.Select(id => new Func<Document, bool>(d => d.HousingDivisions.Any(h => h.HousingDivisionId == id)))
If you absolutely need the type to be an Expression tree, then you can convert to it by casting:
housingDivisions.Select(id => (Expression<Func<Document, bool>>)(d => d.HousingDivisions.Any(h => h.HousingDivisionId == id)))
The compiler suggests explicitly specifying the arguments. Personally I think that way is a little bit more wordy. But it would look like this:
housingDivisions.Select<int, Expression<Func<Document, bool>>>(id => d => d.HousingDivisions.Any(h => h.HousingDivisionId == id));
Here's an extension method for Selecting an Expression:
public static IEnumerable<Expression<Func<ExprArg, Result>>> SelectExpr<TSource, ExprArg, Result>(this IEnumerable<TSource> source, Func<TSource, ExprArg, Result> func)
{
return source.Select((o) => (Expression<Func<ExprArg, Result>>)((arg) => func(o, arg)));
}
// Use:
housingDivisions.SelectExpr((int id, Document d) => d.HousingDivisions.Any(h => h.HousingDivisionId == id));
I know that there're some similar questions to this one, but I'm not being able to fix my issue.
I have the following method:
public IDictionary<string, int> CountXXX(Expression<Func<MessageStatus, bool>> whereFilter = null)
{
try
{
var trackingOpens = whereFilter != null ? _context.MessageStatus.Where(whereFilter).Join(_context.TrackingOpens, x => x.MessageId, g => g.MessageId, (x, g) => x) :
_context.MessageStatus.Join(_context.TrackingOpens, x => x.MessageId, g => g.MessageId, (x, g) => x);
return trackingOpens
.GroupBy(x => x.VariationId)
.Select(g => new { Variation = g.Key.ToString(), Count = g.Count() })
.ToDictionary(x => x.Variation, x => x.Count);
}
catch (Exception e)
{
throw new Exception($"There's been an error trying to count the tracking opens from the database. Details: {e.Message}", e);
}
}
I have the class MessageStatus with VariationId property, I need to group them and count for each one. The problem is that I need to Join with TrackingOpens on MessageId. The Linqstatement here is returning the exception mentioned on the title.
The whereFilter parameter is just another Linq statement that goes inside the .where clause.
TrackingOpens does not have the field VariationId and I cannot add it to that model
Can anyone help me fix this Linq statement?
How to generalize the expression y.Aaa == x.Aaa in the following method?
void Delete<T>(List<T> db, List<T> n, Func<bool> cond) // typed cond
{
var deleted = db
.Where(x => !n.Any(y => y.Aaa == x.Aaa)) // Each T may have different property name?
.ToList();
//....
}
If it cannot be done. How about Delete(db, n, db => db.Aaa, n => n.Aaa)? Or I had to do Delete(db, n, "Aaa")
I think I follow what you are after here.. You would like a generic delete method such as...
void Delete<T>(List<T> db, List<T> n, Func<T, T, bool> cond) // typed cond
{
var deleted = db
.Where(x => !n.Any(y => cond(x, y))) // Each T may have different property name?
.ToList();
//....
}
...and we would call this like...
Delete(db, n, (x, y) => y.Aaa == x.Aaa)
This basically makes cond an "equality comparer" and we can use it inside the Any().
i am trying to query data using linq, i am joining two tables where id == to id of the second table. i am getting an exception error saying
Cannot implicitly convert type
'System.Collections.Generic.List<AnonymousType#1>' to
'System.Collections.Generic.List<--db table here-->'.
var qry = context.Projects
.Join(context.Members, p => p.ID, m => m.ID, (p, m) => new { p, m })
.Where(u => u.m.ID == memId)
.Select(b => new {
b.p.ProjName,
b.p.ProjDesc,
b.p.ProjectType,
b.p.Tags
});
return qry.ToList();
You are trying to return a list of anonymous type from your method but the return type is probably something like List<SomeType>.
So instead of creating anonymous objects you need to create objects of your type.
.Select(b => new SomeType {
// set properties here
});
I have a function which returns a list of property values from a collection:
public static List<string> GetSpeakerList()
{
var Videos = QueryVideos(HttpContext.Current);
return Videos.Where(v => v.Type == "exampleType"
.SelectMany(v => v.SpeakerName)
.Distinct()
.OrderBy(s => s)
.ToList();
}
I'd like to have a generic version which will let me determine which field I'd like projected - say instead of SpeakerName I'd like to allow selecting Video.Length or Video.Type.
I understand that SelectMany takes a Func, so what's the best way to make the Func configurable to allow passing it as a parameter into this function?
Add the function as a parameter to the method.
public static List<string> GetVideosAttribute( Func<Video,string> selector )
{
var Videos = QueryVideos(HttpContext.Current);
return Videos.Where(v => v.Type == "exampleType"
.Select( selector )
.Distinct()
.OrderBy(s => s)
.ToList();
}
var speakers = GetVideosAttribute( v => v->SpeakerName );
var topics = GetVideosAttribute( v => v->Topic );