Good way to combine two List<T>s in .NET 2.0? - .net-2.0

I have two lists I need to form the union of, but I'm in .NET 2.0 so the Union() method appears to be out. These are lists of integers, so no problem with the equality comparisons. What's a good way to go about this?

What about (using Dictionary keys as a hashtable):
public static List<T> Union<T>(List<T> first, List<T> second) {
List<T> newList = new List<T>(first.Count + second.Count);
Dictionary<T, object> firstItems = new Dictionary<T, object>(first.Count);
foreach (T item in first) {
newList.Add(item);
firstItems.Add(item, null);
}
foreach (T item in second) {
if (!firstItems.ContainsKey(item)) {
newList.Add(item);
}
}
return newList;
}
This will maintain the item order in first and second, while still using an O(1) check for duplicate items between the lists

You could just add them together and remove the duplicates:
public List<T> Union<T>(List<T> firstList, List<T> secondList)
{
Dictionary<T, int> tmp = new Dictionary<T, int>();
foreach (T val in firstList)
{
tmp[val] = 1;
}
foreach (T val in secondList)
{
tmp[val] = 1;
}
return new List<T>(tmp.Keys);
}

How about a simple foreach, only adding elements that aren't already in the list:
foreach (int item in list2)
{
if (!list1.Contains(item))
{
list1.Add(item);
}
}
This will preserve the order of the lists.

You could use linqbridge to let you use LINQ to Objects while still targeting Framework 2.0, if you have Visual Studio 2008.
And push, push, push to move to .NET 3.5. LINQ and lambdas change the way you think about code (for the better, IMHO).

Related

Merging Entity Framework Expression Trees

I'm looking for a way to merge multiple expression trees in order to build selectors for an Entity Framework query. The query knows which columns to select based on user-provided parameters. For example, a basic query returns ID/Name columns of an entity. If a parameter is explicitly set to also retrieve the Description column, then the query will return ID/Name/Description.
So, what I need it the code for the MergeExpressions method in the following code.
Expression<Func<T, TDto>> selector1 = x => new TDto
{
Id = x.Id,
Name = x.Name
}
Expression<Func<T, TDto>> selector2 = x => new TDto
{
Description = x.Description
}
var selector = selector1;
if (includeDescription)
selector = MergeExpressions(selector1, selector2);
var results = repo.All().Select(selector).ToList();
Thank you.
Not sure for general case, but merging MemberInitExpression bodied lambdas like in your sample is relatively easy. All you need is to create another MemberInitExpression with combined Bindings:
static Expression<Func<TInput, TOutput>> MergeExpressions<TInput, TOutput>(Expression<Func<TInput, TOutput>> first, Expression<Func<TInput, TOutput>> second)
{
Debug.Assert(first != null && first.Body.NodeType == ExpressionType.MemberInit);
Debug.Assert(second != null && second.Body.NodeType == ExpressionType.MemberInit);
var firstBody = (MemberInitExpression)first.Body;
var secondBody = (MemberInitExpression)second.Body.ReplaceParameter(second.Parameters[0], first.Parameters[0]);
var body = firstBody.Update(firstBody.NewExpression, firstBody.Bindings.Union(secondBody.Bindings));
return first.Update(body, first.Parameters);
}
Note that the lambda expressions must be bound to one and the same parameters, so the above code uses the following parameter replacer helper to rebind second lambda body to the first lambda parameter:
public static partial class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
{
return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
}
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
{
return node == Source ? Target : base.VisitParameter(node);
}
}
}
Check out PredicateBuilder.
Example:
Expression<Func<Customer, bool>> expr1 = (Customer c) => c.CompanyName.StartsWith("A");
Expression<Func<Customer, bool>> expr2 = (Customer c) => c.CompanyName.Contains("B");
var expr3 = PredicateBuilder.And(expr1, expr2);
var query = context.Customers.Where(expr3);
or
var expr3 = expr1.And(expr2);
var query = context.Customers.Where(expr3);
I do this kind of thing with extension methods. Its syntactically a bit nicer than using expression trees everywhere. I call this composable repositories.
I also wrote a tool (LinqExpander) to combine the expression trees of different extension methods togeather, which is especially useful for doing projection (selects) from your database. This is only nessacary when you are doing things with sub-entities. (see my post here: Composable Repositories - Nesting extensions)
usage would be something along the lines of:
var dtos = context.Table
.ThingsIWant() //filter the set
.ToDtos() //project from database model to something else (your Selector)
.ToArray();//enumerate the set
ToDtos might look something like:
public static IQueryable<DtoType> ToDtos(this IQueryable<DatabaseType> things)
{
return things.Select(x=> new DtoType{ Thing = x.Thing ... });
}
You want to merge two selects togeather (im assuming to avoid an underfetch but this seems a bit wierd). I would do this by using a projection like this:
context.Table
.AsExpandable()
.Select(x=>new {
Dto1 = x.ToDto1(),
Dto2 = x.ToDto2()
})
.ToArray();
if you really wanted it to return a single entity like this you could probably do something like:
context.Table
.AsExpandable()
.Select(x=> ToDto1(x).ToDto2(x));
but I havent ever tried this.
As this uses a sub projection you will need the .AsExpandable extensions.

Entity Framework 7 multiple levels of child tables

I'm just getting started with EF7 (CORE) and am struggling to find the right implementation of the following. Say I have a Table with multiple child tables, which in turn have grandchild tables (and these in turn have foreign key tables). If I wanted access to everything I'd need something like this
TABLE_A.Include(c => c.TABLE_B).ThenInclude(co => co.TABLE_C)
.ThenInclude(coi => coi.TABLE_D)
.ThenInclude(coia => coia.TABLE_E)
.Include(c => c.TABLE_B).ThenInclude(co => co.TABLE_F)
.ThenInclude(coa => coa.TABLE_G)
.ThenInclude(coaAcc => coaAcc.TABLE_H)
.ThenInclude(coaAccInt => coaAccInt.TABLE_D)
.ThenInclude(coaAccIntAgent => coaAccIntAgent.TABLE_E)
Now I understand the necessity for chaining the includes to include all of my child tables...but I look at the SQL it fires behind the scenes and its firing off 11 SQL statements. This seems terribly inefficient.
Is this the best way to be doing this? I have now received a new requirement to add 3 more child tables to TABLE_B...so I'll need more includes..and hence more selects running behind the scenes.
I understand the logic behind what I'm doing..and understand lazy loading isn't currently supported in EF7, but this doesn't seem like a very efficient way of doing things when I could write a stored procedure that does it in one go.
Are there best practices for things like this or something I'm not grasping about how to use EF7 to do what I need?
Any help or guidance would be much appreciated!
Thanks
add this extension method to your project, Load method exist in ef 6.x, but not implemented yet in ef core:
public static void Load<TSource, TDestination>(this EntityEntry<TSource> entry, Expression<Func<TSource, IEnumerable<TDestination>>> path, Expression<Func<TDestination, TSource>> pathBack = null) where TSource : class where TDestination : class
{
var entity = entry.Entity;
var context = entry.Context;
var entityType = context.Model.FindEntityType(typeof(TSource));
var keys = entityType.GetKeys();
var keyValues = context.GetEntityKey(entity);
var query = context.Set<TDestination>() as IQueryable<TDestination>;
var parameter = Expression.Parameter(typeof(TDestination), "x");
PropertyInfo foreignKeyProperty = null;
if (pathBack == null)
{
foreignKeyProperty = typeof(TDestination).GetProperties().Single(p => p.PropertyType == typeof(TSource));
}
else
{
foreignKeyProperty = (pathBack.Body as MemberExpression).Member as PropertyInfo;
}
var i = 0;
foreach (var property in keys.SelectMany(x => x.Properties))
{
var keyValue = keyValues[i];
var expression = Expression.Lambda(
Expression.Equal(
Expression.Property(Expression.Property(parameter, foreignKeyProperty.Name), property.Name),
Expression.Constant(keyValue)),
parameter) as Expression<Func<TDestination, bool>>;
query = query.Where(expression);
i++;
}
var list = query.ToList();
var prop = (path.Body as MemberExpression).Member as PropertyInfo;
prop.SetValue(entity, list);
}
public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class
{
var state = context.Entry(entity);
var metadata = state.Metadata;
var key = metadata.FindPrimaryKey();
var props = key.Properties.ToArray();
return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray();
}
then whenever you need each of navigation properties, before use first call load (just once for any navigation properties) method as fallowing:
//for first item
var item = TABLE_A.First();
context.Entry(item ).Load(b => b.TABLE_B);
Depending on your use case, can Include or ThenInclude some of navigation in first query that load TABLE_A.
Load extension method Source Link with more examples

Combining Includes with Entity Framework

I generally use a generic repository to boilerplate my EF queries so I have to write limited code and also use caching. The source code for the repository can be found here.
The backbone query within the code is this one below. FromCache<T>() is an IEnumerable<T> extension method that utilizes the HttpContext.Cache to store the query using a stringified representation of the lambda expression as a key.
public IQueryable<T> Any<T>(Expression<Func<T, bool>> expression = null)
where T : class, new()
{
// Check for a filtering expression and pull all if not.
if (expression == null)
{
return this.context.Set<T>()
.AsNoTracking()
.FromCache<T>(null)
.AsQueryable();
}
return this.context.Set<T>()
.AsNoTracking<T>()
.Where<T>(expression)
.FromCache<T>(expression)
.AsQueryable<T>();
}
Whilst this all works it is subject to the N+1 problem for related tables since If I were to write a query like so:
var posts = this.ReadOnlySession.Any<Post>(p => p.IsDeleted == false)
.Include(p => p.Author);
The Include() will have no effect on my query since it has already been run in order to be cached.
Now I know that I can force Entity Framework to use eager loading within my model by removing the virtual prefix on my navigation properties but that to me feels like the wrong place to do it as you cannot predict the types of queries you will be making. To me it feels like something I would be doing in a controller class. What I am wondering is whether I can pass a list of includes into my Any<T>() method that I could then iterate though when I make the call?
ofDid you mean something like...
IQueryable<T> AnyWithInclude<T,I>(Expression<Func<T,bool>> predicate,
Expression<Func<T,I>> includeInfo)
{
return DbSet<T>.where(predicate).include(includeInfo);
}
the call
Context.YourDbSetReference.AnyWithInclude(t => t.Id==someId, i => i.someNavProp);
In response to extra question on as collection.
I realised late, there was an overload on Property. You can just pass a string
This might work but call is not easy. Well I find it hard.
IQueryable<T> GetListWithInclude<I>(Expression<Func<T, bool>> predicate,
params Expression<Func<T, I>>[] IncludeCollection);
so i tried
public virtual IQueryable<T> GetListWithInclude(Expression<Func<T, bool>> predicate,
List<string> includeCollection)
{ var result = EntityDbSet.Where(predicate);
foreach (var incl in includeCollection)
{
result = result.Include(incl);
}
return result;
}
and called with
var ic = new List<string>();
ic.Add("Membership");
var res = context.DbSte<T>.GetListWithInclude( t=>t.UserName =="fred", ic);
worked as before.
In the interest of clarity I'm adding the solution I came up with based upon #soadyp's answer.
public IQueryable<T> Any<T>(Expression<Func<T, bool>> expression = null,
params Expression<Func<T, object>>[] includeCollection)
where T : class, new()
{
IQueryable<T> query = this.context.Set<T>().AsNoTracking().AsQueryable<T>();
if (includeCollection.Any())
{
query = includeCollection.Aggregate(query,
(current, include) => current.Include(include));
}
// Check for a filtering expression and pull all if not.
if (expression != null)
{
query = query.Where<T>(expression);
}
return query.FromCache<T>(expression, includeCollection)
.AsQueryable<T>();
}
Usage:
// The second, third, fourth etc parameters are the strongly typed includes.
var posts = this.ReadOnlySession.Any<Post>(p => p.IsDeleted == false,
p => p.Author);

Rx: operator for getting first and most recent value from an Observable stream

For an Rx based change tracking solution I am in need of an operator which can get me the first and most recent item in an observable sequence.
How would I write an Rx operator that produces the following marble diagram (Note: the brackets are used just to lineup the items...I'm not sure how best to represent this in text):
xs:---[a ]---[b ]-----[c ]-----[d ]---------|
desired:---[a,a]---[a,b]-----[a,c]-----[a,d]---------|
Using the same naming as #Wilka you can use the below extension which is somewhat self-explanatory:
public static IObservable<TResult> FirstAndLatest<T, TResult>(this IObservable<T> source, Func<T,T,TResult> func)
{
var published = source.Publish().RefCount();
var first = published.Take(1);
return first.CombineLatest(published, func);
}
Note that it doesn't necessarily return a Tuple, but rather gives you the option of passing a selector function on the result. This keeps it in line with the underlying primary operation (CombineLatest). This is obviously easily changed.
Usage (if you want Tuples in the resulting stream):
Observable.Interval(TimeSpan.FromSeconds(0.1))
.FirstAndLatest((a,b) => Tuple.Create(a,b))
.Subscribe(Console.WriteLine);
Try this:
public static IObservable<Tuple<T, T>> FirstAndLatest<T>(
this IObservable<T> source)
{
return
source
.Take(1)
.Repeat()
.Zip(source, (x0, xn) => Tuple.Create(x0, xn));
}
Simple, huh?
Or, as an alternative to share the underlying source, try this:
public static IObservable<Tuple<T, T>> FirstAndLatest<T>(
this IObservable<T> source)
{
return
source.Publish(
s =>
s.Take(1)
.Repeat()
.Zip(s, (x0, xn) => Tuple.Create(x0, xn)));
}
WHOOPS! Scratch this. It doesn't work. It essentially keeps producing a pair of the latest values. Publishing like this isn't working. The original implementation is the best.
I suspect there's a much better way of doing this (and I dislike using Do), but you could create an operator like this
public static IObservable<Tuple<T, T>> FirstAndLatest2<T>(this IObservable<T> source)
{
return Observable.Defer(() => {
bool hasFirst = false;
T first = default(T);
return source
.Do(item =>
{
if (!hasFirst)
{
hasFirst = true;
first = item;
}
})
.Select(current => Tuple.Create(first, current));
});
}
Then you would use it like this:
Observable.Interval(TimeSpan.FromSeconds(0.1))
.FirstAndLatest()
.Subscribe(Console.WriteLine);

IN with linq to object [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Shorthand conditional in C# similar to SQL 'in' keyword
I have a string variable which holds states. I want to check whether it equals to one of these three. I want it to work the way IN works in SQL Server. IS it possible to do with Linq to Objects.
i want
if(str IN ("WA","CA","CO"))
{
}
else
{
}
How to do it. I donot want to use multiple OR conditions.
unfortunately there is no IN, but you can say this
if (new[] { "WA", "CA", "CO" }.Contains(str))
{
}
It seems the wrong way around but it's the best we've got.
How about
if ((new string [] {"WA", "CA", "CO"}).Contains(str))
{
}
else
{
}
This is using the .Contains() extension method on IEnumerable<> - not full LINQ but it should work. In production code you'd want to extract the array
new string[] {"WA", "CA", "CO"}
out to a local field.
You can make an extension method:
public static class Extensions {
public static bool In<T>(this T value, params T[] options) : where T : IComparable<T> {
foreach (T option in options) {
if (value.CompareTo(option) == 0) return true;
}
return false;
}
}
Usage:
var result = someCollection.Where(x => x.Property.In(1,2,3));