merging 2 collections and find all the unique items - linq

I have 2 collections need to create a 3 one if you like by merging the 2 and giving me a third one with all the unique items only
class Program
{
static void Main(string[] args)
{
ObservableCollection<Person> collectionA = new ObservableCollection<Person>
{
new Person {Id = 1, Name = "Name1", Surname = "Surname1"},
new Person {Id = 2, Name = "Name2", Surname = "Surname2"},
new Person {Id = 3, Name = "Name3", Surname = "Surname3"},
new Person {Id = 4, Name = "Name4", Surname = "Surname4"}
};
ObservableCollection<Person> collectionB = new ObservableCollection<Person>
{
new Person {Id = 5, Name = "Name5", Surname = "Surname5"},
new Person {Id = 2, Name = "Name2", Surname = "Surname2"},
new Person {Id = 6, Name = "Name6", Surname = "Surname6"},
new Person {Id = 4, Name = "Name4", Surname = "Surname4"}
};
ObservableCollection<Person> result=????
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
}
Any ideas?Thanks a lot
EDIT CLARIFICATION
I have collectionA, then I create collection B, compare the two collection add any item to FIND ALL THE ITEMS IN COLLECTIONB THAT DONT EXISTS IN COLLECTION A AND CREATE A RESULT COLLECTION.Hope clear now

If Id is a unique identifier of you person try this one:
ObservableCollection<Person> result = new ObservableCollection<Person>(collectionB
.Where(p => !collectionA.Any(p2=>p2.Id==p.Id)));

Edited answer:
ObservableCollection<Person> result = new ObservableCollection<Person>(collectionB.Except(collectionA));
Note that this will create a new collection that is not tied to the old collections - so if you add a person to collectionA, they will not show up in result automatically.

Related

How to write a Linq that can retrieve all parent table records and total of sub-table record, I mean 'separate' into two parts

Let's say I have two tables, parent table 'P' and sub-table 'S', I usually wrote the Linq like this to get what I want:
var rows = from p in db.P
join s in db.S on p.Id equals s.ParentId into subContent
where (some condition here)
select new{
Id = p.Id,
Title = p.Title
SubContentCount = subContent.Count()
}
It's very simple, but if for some reason I have to pass a parameter into this query when there has one (let's say 'key'), I have to do this (I guess :-):
var rows = from p in db.P
join s in db.S on p.Id equals s.ParentId into subContent
where (some condition here)
select p;
if(!string.IsNullOrEmpty(key)){ // I'm using C#
rows = rows.Where(q => q.Title.Contains(key))
}
And then:
var list = rows.Select(q => new ()
{
Id = q.Id,
Title = q.Title,
subCount = ???.Count()
});
Is that passable to do Linq like this? if so, how?
Thanks for any kind help!
You could create a method that receives a Func<Table, bool>as parameter and use it to filter your dataset:
public static void Main(string[] args)
{
var rows = new List<Table>
{
new Table { Id = 1, Title = "A", SubContent = new [] { "A1" } },
new Table { Id = 2, Title = "B", SubContent = new [] { "B1", "B2" } },
new Table { Id = 3, Title = "C", SubContent = new [] { "C1", "C2", "C3" } },
};
var title = "C";
foreach (var item in Filter(rows, table =>
String.IsNullOrEmpty(title) || table.Title == title))
{
Console.WriteLine(
"Title={0}, SubContent.Length={1}",
item.Title, item.SubContent.Length);
}
}
public static List<Table> Filter(List<Table> original, Func<Table, bool> filter)
{
return original.Where(filter).ToList();
}
public class Table
{
public int Id { get; set; }
public string Title { get; set; }
public string[] SubContent { get; set; }
}
Why not include the filter in the where clause?
where string.IsNullOrEmpty(key) || p.Title.Contains(key)
Quick example in the interactive console:
public class Parent { public int Id {get; set;} public string Title {get; set;} }
public class SubTable { public int Id {get; set;} public int ParentId {get; set;} }
public class Result { public int Id {get; set;} public string Title {get; set;} public int SubContentCount {get; set;} }
var p1 = new Parent() { Id = 1, Title = "Parent_1" };
var p2 = new Parent() { Id = 2, Title = "Parent_2" };
var p3 = new Parent() { Id = 3, Title = "Parent_3" };
var s1_1 = new SubTable() { Id = 11, ParentId = 1 };
var s1_2 = new SubTable() { Id = 12, ParentId = 1 };
var s1_3 = new SubTable() { Id = 13, ParentId = 1 };
var s2_1 = new SubTable() { Id = 21, ParentId = 2 };
var s2_2 = new SubTable() { Id = 22, ParentId = 2 };
var s3_1 = new SubTable() { Id = 31, ParentId = 3 };
var db_P = new List<Parent>() { p1, p2, p3 };
var db_S = new List<SubTable>() { s1_1, s1_2, s1_3, s2_1, s2_2, s3_1 };
public IEnumerable<Result> GetResults(string key = null)
{
var rows = from p in db_P
join s in db_S on p.Id equals s.ParentId into subContent
where string.IsNullOrEmpty(key) || p.Title.Contains(key)
select new Result() {
Id = p.Id,
Title = p.Title,
SubContentCount = subContent.Count()
};
return rows;
}
And example output (formatted onto multiple lines for readability)
> GetResults().ToList()
List<Submission#0.Result>(3) {
Submission#0.Result { Id=1, SubContentCount=3, Title="Parent_1" },
Submission#0.Result { Id=2, SubContentCount=2, Title="Parent_2" },
Submission#0.Result { Id=3, SubContentCount=1, Title="Parent_3" }
}
> GetResults("1").ToList()
List<Submission#0.Result>(1) {
Submission#0.Result { Id=1, SubContentCount=3, Title="Parent_1" }
}
>

In Nest, how do I specify a child document's parent document while indexing?

Product and Company are in a many-to-one child-parent relationship:
[ElasticType(Name = "product", IdProperty = "ProductId")]
internal class Product
{
public int ProductId { get; set; }
public string Title { get; set; }
}
[ElasticType(Name = "company", IdProperty = "CompanyId")]
public class Company
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
}
In the mapping of Product, I did:
Func<PutMappingDescriptor<Product>, PutMappingDescriptor<Product>> descriptor = m => m
.MapFromAttributes()
.AllField(a => a.Enabled(false))
.SetParent<Company>();
I created a parent and child:
var company = new Company {
CompanyId = 1,
CompanyName = "XYZ Company"
};
var p2 = new Product{
ProductId = 2,
Title = "ABC Product"
};
es.Index(company);
The problem is then, how do I index p2? With only the Index method, I can only do es.Index(p2). But where do I indicate that p2 should be indexed under the parent company?
Basically I wanted a NEST solution to PUT /myindex/product/2?parent=1.
The closest answer I found so far is in https://stackoverflow.com/a/23953742/1124270. But the answer uses bulk inserts like the following where you have a .Parent method in the chaining to specify the parent's ID:
var bulkResponse = _client.Bulk(b => b
.Index<Address>(bd => bd.Object(new Address { Name = "Tel Aviv", Id = 1 }).Index("test"))
.Index<Person>(bd => bd.Index("test").Object(new Person {Id = 5, Address = 1, Name = "Me"}).Parent(1)));
If you are looking for PUT /myindex/product/2?parent=1 request.
You can do this in the NEST in a such way:
var indexResponse = client.Index(p2, descriptor => descriptor
.Parent(company.CompanyId.ToString()));
which generates below request to elasticsearch
StatusCode : 400,
Method : PUT,
Url : http : //localhost:9200/indexname/product/2?parent=1,
Request : {
"productId" : 2,
"title" : "ABC Product"
}

Get tuple and list linked as result

I have this query :
var query = (from tables ...
where ...
select new
{
ClientName = ClientName,
ClientNumber = ClientNumber,
ClientProduct = ClientProduct
}).Distinct();
which returns rows with 3 values.
ClientName and ClientNumber can be linked to multiple products.
So we can have :
NameA NumberA Product1
NameA NumberA Product2
NameA NumberA Product3
NameB NumberB Product4
NameC NumberC Product5
I would like to know if it is possible to store that in a List of a certain class which would be like :
class MyClass
{
string ClientName,
int ClientNumber,
List<int> ClientProducts
}
So there are no duplicate of ClientName and ClientNumber.
Thank you in advance.
With this class structure to represent your data:
class MyClass
{
public string ClientName { get; set; }
public int ClientNumber { get; set; }
public List<int> ClientProducts { get; set; }
}
class Procuct
{
public string ClientName { get; set; }
public int ClientNumber { get; set; }
public int ProductID { get; set; }
}
and this test data:
List<Procuct> Products = new List<Procuct>()
{
new Procuct() { ClientName = "A", ClientNumber = 1, ProductID = 1},
new Procuct() { ClientName = "A", ClientNumber = 1, ProductID = 2},
new Procuct() { ClientName = "A", ClientNumber = 1, ProductID = 3},
new Procuct() { ClientName = "B", ClientNumber = 2, ProductID = 4},
new Procuct() { ClientName = "C", ClientNumber = 2, ProductID = 5}
};
you can use the following linq query:
var q = from p in Products
group p by new
{
cName = p.ClientName,
cNumber = p.ClientNumber
} into pGroup
select new MyClass
{
ClientName = pGroup.Key.cName,
ClientNumber = pGroup.Key.cNumber,
ClientProducts = pGroup.Select(x => x.ProductID).ToList()
};
to get exactly what you want, i.e. a collection of MyClass objects.
The Grouping performed in the above linq query essentially guarantees that there will be no duplicates on (ClientName, ClientNumber).
Since you mention Linq-to-sql, most probably you Client entity already has the products linked. You might look for an overcomplicated solution.
It depends a bit on your foreign key stucture, but if your datamodel would be
Client has 1-many product and you have a Foreign key from product to client it is already present.
So you can just reference client.Products.
So in your case it would be
var query = (from Clients...
where ...
select new
{
ClientName = Client.ClientName,
ClientNumber = Client.ClientNumber,
ClientProduct = Client.Products.Select(s=>s.id).ToList()
});
But you might as well simply use your client entity with a eager load of the products.
It all depends on your datamodel + proper foreign key structure
if you have a many-many associations like Product-per-client between your client and product you can start from that entity. Have a look at this documentation - it provides a good starting point for Linq-2-sql.
http://weblogs.asp.net/scottgu/using-linq-to-sql-part-1
I solve same problem , I think it useful to you
Only check your Where Condition properly
Thank...
var query = (from tables ...
where ...
select new
{
ClientName = ClientName,
ClientNumber = ClientNumber,
ClientProduct = ClientProduct.ToList()
}).Distinct();

Nested LINQ query

I'm trying to perform a nested linq query.
public class Sic
{
public int Id { get; set; }
public string Code { get; set; }
}
public class Message
{
public List<Sic> Sics { get; set; }
public int Id { get; set; }
}
List<Message> msgList = new List<Message>();
Message m1 = new Message
{
Id = 0,
Sics = new List<Sic>()
{
new Sic() {Id = 0, Code = "A2A"},
new Sic() {Id = 1, Code = "A2B"},
new Sic() {Id = 2, Code = "A2C"},
new Sic() {Id = 3, Code = "A2D"}
}
};
Message m2 = new Message
{
Id = 1,
Sics = new List<Sic>()
{
new Sic() {Id = 4, Code = "B2A"},
new Sic() {Id = 5, Code = "B2B"},
new Sic() {Id = 6, Code = "B2C"},
new Sic() {Id = 7, Code = "B2D"}
}
};
msgList.Add(m1);
msgList.Add(m2);
List<string> searchList = new List<string> {"A2A", "A2B"};
I want to find messages in msgList where searchList is contained by the Sics of each each message, i.e. m1 should be found using the above searchList.
You can use something like,
msgList.Where(msg=>msg.Sics.Any(sic=>searchList.Contains(sic.Code)));
or if you need to match all search terms,
msgList.Where(msg => searchList.All(searchTerm=>msg.Sics.Any(sic=>sic.Code==searchTerm)))
If all ids in searchlist need to be matched
msgList.Where(msg => searchList.Any() && searchList.All(s => msg.Sics.Any(sic => s==sic.Code)))
If any id in searchlist need to be matched
msgList.Where(msg=>msg.Sics.Any(sic=>searchList.Contains(sic.Code)));

Entity Framework Code First and populating join tables

I been practicing with EF Code First, SQL Express, and ASP.Net MVC3.
When I run the website first the correct tables are generated by the FooInitializer and Student and Image are populated but for some reason the join table (StudentImages) is not being populated.
What could be the issue?
Tables: Student, Image, and StudentImages
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Image> Images { get; set; }
}
public class Image
{
public int Id { get; set; }
public string Filename { get; set; }
public string Extension { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class FooInitializer : DropCreateDatabaseIfModelChanges<DBContext>
{
protected override void Seed(DBContext context)
{
var students = new List<Student> {
new Student { Id = 1, Name = "John" },
new Student { Id = 2, Name = "Jane" }
};
students.ForEach(s => context.Students.Add(s));
context.SaveChanges();
var images = new List<Image> {
new Image { Id = 1, Filename = "IMG_4596.JPG", Extension = ".jpg" },
new Image { Id = 2, Filename = "IMG_4600.JPG", Extension = ".jpg" }
};
images.ForEach(i => context.Images.Add(i));
students[0].Images.Add(images[0]);
context.SaveChanges();
}
}
From what I can tell your Image class does not have a reference to the StudentID. Try adding:
public int StudentID { get; set; }
to the Image class maybe?
Also having an ICollection would mean that one image could have multiple students - is this correct? Maybe it should be a public virtual Student Student {...}
EDIT: Also I found this, with a many to many relationship (if thats what you need):
In your OnModelCreating() Method:
modelBuilder.Entity<Student>()
.HasMany(c => c.Images).WithMany(i => i.Students)
.Map(t => t.MapLeftKey("StudentId")
.MapRightKey("ImageID")
.ToTable("StudentImages"));
taken from this link that states:
A many-to-many relationship between the Instructor and Course
entities. The code specifies the table and column names for the join
table. Code First can configure the many-to-many relationship for you
without this code, but if you don't call it, you will get default
names such as InstructorInstructorID for the InstructorID column.
EDIT: Here is the code I used the other night, with my implementation of the code first MVC site:
var users = new List<User>
{
new User { UserID = new Guid(), Email = "me#me.com", LastOnline = DateTime.Now, Password = "pword", RegistrationDate = DateTime.Now, SecurityAnswer = "me", SecurityQuestion = "who?", Roles = new List<Role>() },
};
users.ForEach(s => context.Users.Add(s));
context.SaveChanges();
var roles = new List<Role>
{
new Role { RoleID = "Admin", Description = "Administration Users", Users = new List<User>() }
};
roles.ForEach(r => context.Roles.Add(r));
users[0].Roles.Add(roles[0]);
context.SaveChanges();
var userLicense = new List<UserLicense>
{
new UserLicense { AddDateTime = DateTime.Now, LicenseType = "Farmer", Manufacturer = "Motorola", Model = "Droid", PhoneIdentifier = "c0e4223a910f", UserID = users[0].UserID, User = new User() }
};
userLicense[0].User = users[0];
userLicense.ForEach(u => context.UserLicenses.Add(u));
context.SaveChanges();
userLicense[0].User = users[0];
context.SaveChanges();
Notice in each instantiated item, I am also instantiating a new referenced item within the parent object.
EDIT:
Ok try this:
var students = new List<Student> {
new Student { Id = 1, Name = "John", Images = new List<Image>() },
new Student { Id = 2, Name = "Jane", Images = new List<Image>() }
};
students.ForEach(s => context.Students.Add(s));
context.SaveChanges();
var images = new List<Image> {
new Image { Id = 1, Filename = "IMG_4596.JPG", Extension = ".jpg", Students = new List<Student>() },
new Image { Id = 2, Filename = "IMG_4600.JPG", Extension = ".jpg", Students = new List<Student>() }
};
images.ForEach(i => context.Images.Add(i));
students[0].Images.Add(images[0]);
students[1].Images.Add(images[1]);
context.SaveChanges();
Try adding this before saving changes for each student:
foreach (Image i in s1.Images)
context.ObjectStateManager.ChangeObjectState(i, System.Data.EntityState.Added);
Also try with System.Data.EntityState.Modified.
Hope this works...

Resources