How to select only those records from collection which have relation with another table using Linq - c#

Hi there I have 2 classes called SlownikRyzyk and Ryzyko. I create new variable called query. I want to insert to query only those records from SlownikRyzyk which have relation with the records in Class Ryzyko. I found the way how to do that by using pure linq but I want to know how to do this with lambda expression.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LinqTraining
{
class SlownikRyzyk
{
public int Id { get; set; }
public string NazwaRyzyka { get; set; }
public static List<SlownikRyzyk> getListSlownikRyzyk()
{
List<SlownikRyzyk> listSlownikRyzyk = new List<SlownikRyzyk>
{
new SlownikRyzyk
{
Id=1,
NazwaRyzyka="Włamanie"
},
new SlownikRyzyk
{
Id=2,
NazwaRyzyka="Napad"
},
new SlownikRyzyk
{
Id=3,
NazwaRyzyka="Pożar"
},
new SlownikRyzyk
{
Id=4,
NazwaRyzyka="Zepsute zamki"
}
};
return listSlownikRyzyk;
}
}
class Ryzyko
{
public int Id { get; set; }
public string Opis { get; set; }
public int SlownikRyzykId { get; set; }
public static List<Ryzyko> getListRyzyko()
{
List<Ryzyko> listRyzyko = new List<Ryzyko>
{
new Ryzyko
{
Id=11,
Opis="Pożar piwnicy może grozić stratą wielu ton papieru",
SlownikRyzykId=3
},
new Ryzyko
{
Id=12,
Opis="Ktoś może zatrzasnąć się w pokuju",
SlownikRyzykId=0
},
new Ryzyko
{
Id=14,
Opis="Ktoś może napaść na kase",
SlownikRyzykId=0
},
new Ryzyko
{
Id=17,
Opis="Przez włamanie do biur mogą zostać wykradzione pufne dane frimy",
SlownikRyzykId=1
}
};
return listRyzyko;
}
}
class Program
{
static void Main(string[] args)
{
var query = from r in Ryzyko.getListRyzyko()
from s in SlownikRyzyk.getListSlownikRyzyk()
where s.Id == r.SlownikRyzykId
select s;
foreach (var a in query)
{
Console.WriteLine(a.NazwaRyzyka);
}
}
}
}

Try like this
var query=Ryzyko.getListRyzyko().
Join(SlownikRyzyk.getListSlownikRyzyk(),
r=>r.SlownikRyzykId,
s=>s.Id,
(r,s)=> new {R=r,S=s} )

Related

C# Create XML with unlimited child nodes based on number property

I have the following C# class in my project:
public class Department
{
public string Name { get; set; }
public string Number{ get; set; }
public List<Department> SubDepartments{ get; set; }
}
A department can have sub-departments that have sub-departments on their own. The Number property determines the parent-child relationship and there is no limit for the depth.
I have a feed with a collection of departments that have only Name and Number and no SubDepartments. Which is the best way to create a XML file with child nodes for sub-departments based on the Number property?
Example:
<MainDepartment name="IT" number="1">
<SubDepartment name="Software engineering" number="1.1" >
<SubDepartment name="Quality assurance" number="1.1.1">
...
</SubDepartment>
<SubDepartment name="Development" number="1.1.2" />
</SubDepartment>
<SubDepartment name="Support" number="1.2" />
<SubDepartment name="Administration" number="1.3" />
</MainDepartment>
<MainDepartment name="Finance" number="2" >
<SubDepartment name="Accounting" number="2.1">
...
</SubDepartment>
</MainDepartment>
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
List<Department> departments = new List<Department>() {
new Department() { Name = "IT", Number = "1", SubDepartments = new List<Department>() {
new Department() { Name = "Software engineering", Number = "1.1", SubDepartments = new List<Department>() {
new Department() { Name = "Quality assurnace", Number = "1.1.1"},
new Department() { Name = "Development", Number = "1.1.2"}
}},
new Department() { Name = "Support", Number = "1.2"},
new Department() { Name = "Administration", Number = "1.3"}
}},
new Department() { Name = "Finance", Number = "2", SubDepartments = new List<Department>() {
new Department() { Name = "Accounting", Number = "2.1"}
}}
};
string header = "<Company></Company>";
XDocument doc = XDocument.Parse(header);
XElement company = doc.Root;
int level = 1;
CreateXml(departments, company, level);
doc.Save(FILENAME);
}
static void CreateXml(List<Department> parentDept, XElement parentXml, int level)
{
foreach (Department department in parentDept)
{
XElement newDept;
if (level == 1)
{
newDept = new XElement("MainDepartment");
}
else
{
newDept = new XElement("SubDepartment");
}
parentXml.Add(newDept);
newDept.Add(new XAttribute("name", department.Name));
newDept.Add(new XAttribute("number", department.Number));
if (department.SubDepartments != null)
{
CreateXml(department.SubDepartments, newDept, level + 1);
}
}
}
}
public class Department
{
public string Name { get; set; }
public string Number { get; set; }
public List<Department> SubDepartments { get; set; }
}
}

Data not seeding into database

I am following a tutorial on the documentation to try create my own database. The data was seeding properly with 3 tables and now I have added 6 I can't get the data to seed. I have tried creating a migration and updating the database. I did change some of the ON DELETE CASCADE to ON DELETE NO ACTION as I was getting an error with cascading and I am not sure if that is the reason that it isn't seeding.
For reference it was the tables 'Car' , 'PaymentPlan' & 'SalesMan' that was working previously
Initialise code:
using GarageSales.Data;
using GarageSales.Models;
using System;
using System.Linq;
namespace GarageSales.Data
{
public static class DbInitializer
{
public static void Initialize(GarageSalesContext context)
{
//context.Database.EnsureCreated();
// Look for any Cars.
if (context.Cars.Any())
{
return; // DB has been seeded
}
var Customers = new Customer[]
{
new Customer{FirstName="Ray", LastName="Easton", Gender="Male", Address="2 Church Road", PostCode="BT35 0JW", RentalID=1, CarID=1, SalesManID=1},
new Customer{FirstName="Amelie", LastName="Bush", Gender="Female", Address="54 Beach Gardens", PostCode="BT34 0JE", RentalID=2, CarID=2, SalesManID=2},
new Customer{FirstName="Ray", LastName="Easton", Gender="Male", Address="2 Church Road", PostCode="BT67 0JW", RentalID=3, CarID=3, SalesManID=3}
};
foreach (Customer customer in Customers)
{
context.Customer.Add(customer);
}
context.SaveChanges();
var Cars = new Car[]
{
new Car{Model="I8",Manufacturer="BMW",EngineSize="1.5 L 3-cylinder"},
new Car{Model="A5",Manufacturer="Audi",EngineSize="5.2 L V10"},
new Car{Model="R8",Manufacturer="Audi",EngineSize="1.5 L 3-cylinder"}
};
foreach (Car car in Cars)
{
context.Cars.Add(car);
}
context.SaveChanges();
var SalesMen = new SalesMan[]
{
new SalesMan{FirstName="Darren",SurName="Dooning"},
new SalesMan{FirstName="Jim",SurName="Campbell"},
new SalesMan{FirstName="Jade",SurName="Mull"},
};
foreach (SalesMan SalesMan in SalesMen)
{
context.SalesMen.Add(SalesMan);
}
context.SaveChanges();
var Rentals = new Rental[]
{
new Rental{Price=150, Duration=36, Quote=3500, CustomerID=1, CarID=1, SalesManID=1},
new Rental{Price=200, Duration=24, Quote=2000, CustomerID=2, CarID=2, SalesManID=2},
new Rental{Price=400, Duration=12, Quote=4500, CustomerID=3, CarID=3, SalesManID=3}
};
foreach (Rental Rental in Rentals)
{
context.Rental.Add(Rental);
}
context.SaveChanges();
var PaymentPlans = new PaymentPlan[]
{
new PaymentPlan{CarID=1,SalesManID=1},
new PaymentPlan{CarID=2,SalesManID=2},
new PaymentPlan{CarID=3,SalesManID=3}
};
foreach (PaymentPlan PaymentPlan in PaymentPlans)
{
context.PaymentPlans.Add(PaymentPlan);
}
context.SaveChanges();
var Duration = new Duration[]
{
new Duration{DurationLength=36, RentalID=1, SalesManID=1},
new Duration{DurationLength=24, RentalID=2, SalesManID=2},
new Duration{DurationLength=12, RentalID=3, SalesManID=3}
};
foreach (Duration duration in Duration)
{
context.Duration.Add(duration);
}
context.SaveChanges();
}
}
}
Context class (The dataSets are 2 different ways as I figured late on and would have to go and change it to make the program run):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using GarageSales.Models;
namespace GarageSales.Data
{
public class GarageSalesContext: DbContext
{
public GarageSalesContext (DbContextOptions<GarageSalesContext> options)
: base(options)
{
}
public DbSet<Car> Cars { get; set; }
public DbSet<PaymentPlan> PaymentPlans { get; set; }
public DbSet<SalesMan> SalesMen { get; set; }
public DbSet<GarageSales.Models.Customer> Customer { get; set; }
public DbSet<GarageSales.Models.Duration> Duration { get; set; }
public DbSet<GarageSales.Models.Rental> Rental { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>().ToTable("Car");
modelBuilder.Entity<PaymentPlan>().ToTable("PaymentPlan");
modelBuilder.Entity<SalesMan>().ToTable("SalesMan");
modelBuilder.Entity<Duration>().ToTable("Duration");
modelBuilder.Entity<Rental>().ToTable("Rental");
modelBuilder.Entity<Customer>().ToTable("Customer");
}
}
}
If you need anymore information just ask

Linq Collection Sorting

I need to sort countries in this collection using LINQ:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
class Country
{
public string Name { get; set; }
public int Population { get; set; }
public Country(string name, int population)
{
Name = name;
Population = population;
}
}
static void Main(string[] args)
{
Country[] countryCollection =
{
new Country("Afghanistan", 34656032),
new Country("Austria", 8857960),
new Country("Brazil", 210147125),
new Country("Denmark", 5789957),
new Country("Russia", 144526636),
new Country("China", 1403500365),
new Country("Turkey", 80810525),
new Country("Serbia", 7001444),
new Country("Iraq", 37202572),
new Country("San Marino", 33344)
};
}
}
}
It should be sorted by population and printed that way.
This should do what you want
class Program
{
static void Main(string[] args)
{
List<Country> countryCollection = new List<Country>() {
new Country("Afghanistan",34656032),
new Country("Austria", 8857960),
new Country("Brazil", 210147125),
new Country("Denmark", 5789957),
new Country("Russia", 144526636),
new Country("China", 1403500365),
new Country("Turkey", 80810525),
new Country("Serbia", 7001444),
new Country("Iraq", 37202572),
new Country("San Marino", 33344) };
var OrderedCountries = countryCollection.OrderByDescending(x => x.Population).ToList();
foreach (var country in OrderedCountries)
{
Console.WriteLine($"The country {country.Name} has {country.Population} people");
}
}
}
public class Country
{
public string Name { get; set; }
public int Population { get; set; }
public Country(string name, int population)
{
Name = name;
Population = population;
}
}
You can use a list or if you want to maintain an array you can use a delegate to anonymous method:
static void Main(string[] args)
{
Country[] countryCollection = {
new Country("Afghanistan", 34656032),
new Country("Austria", 8857960),
new Country("Brazil", 210147125),
new Country("Denmark", 5789957),
new Country("Russia", 144526636),
new Country("China", 1403500365),
new Country("Turkey", 80810525),
new Country("Serbia", 7001444),
new Country("Iraq", 37202572),
new Country("San Marino", 33344)
};
Array.Sort(countryCollection, delegate(Country country1, Country country2) {
return country1.Population.CompareTo(country2.Population);
});
foreach (Country country in countryCollection) Console.WriteLine("Country name: " + country.Name + " Population: " + country.Population);
Console.ReadKey();
}
See http://www.csharp-examples.net/sort-array/ for more details.
You could convert the array into a List, order it by population, and then convert it back into an array.
countryCollection = countryCollection.ToList().OrderBy(x => x.Population).ToArray();
Or if you want to order it by descending population instead:
countryCollection = countryCollection.ToList().OrderByDescending(x => x.Population).ToArray();

How to map nested Property with Automapper

I am trying to map Student with StudentDto, this is what I am doing but it is complaining about the nested property which is of type List<StudentContact>
Both the objects, StudentDto and Student have exactly the same properties, this is what i am using to try to map the objects.
var config = new MapperConfiguration(
cfg => cfg.CreateMap<StudentDto, Student>());
var mapper = config.CreateMapper();
var driverActivationResponse = mapper.Map <List<Student> > (studentDto);// "studentDto" is List<StudentDto>
my classes
public class StudentDto
{
public StudentDto()
{
if(StudentContacts==null) StudentContacts=new List<StudentContact>();
}
public string Id { get; set; }
public List<StudentContact> StudentContacts { get; set; }
}
public class Student
{
public Student()
{
if(StudentContacts==null) StudentContacts=new List<StudentContact>();
}
public string Id { get; set; }
public List<StudentContact> StudentContacts { get; set; }
}
public class StudentContact
{
public string ContactName { get; set; }
public string PrimaryContactNo { get; set; }
}
This should help -
AutoMapper.Mapper.CreateMap<Student, StudentDto>()
.ForMember(a => a.StudentContacts, b => b.ResolveUsing(c => c.StudentContacts));
var map = Mapper.Map<StudentDto>(new Student
{
Id = "100",
StudentContacts = new List<StudentContact>
{
new StudentContact{ContactName = "test",PrimaryContactNo = "tset"}
}
});
you cannot map like mapper.Map <List<Student>>(studentDto);. The top level member cannot be a list when using automapper.
Does it help to specify the source collection type and destination collection type in your Map call?
var driverActivationResponse = mapper.Map<List<Student>, List<StudentDto>>(studentDto);
It looks like the AutoMapper code you have is correct. If you're still getting an error, something else must be wrong. Perhaps your studentDto is not really a List<StudentDto>?
In any case, here's an entire example that works without error:
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
namespace ConsoleSandbox
{
class Program
{
public static void Main()
{
var config = new MapperConfiguration(
cfg => cfg.CreateMap<StudentDto, Student>());
var mapper = config.CreateMapper();
var studentDtos = new[]
{
new StudentDto
{
Id = "1",
StudentContacts = new[]
{
new StudentContact { ContactName = "Dan", PrimaryContactNo = "123" },
new StudentContact { ContactName = "Stan", PrimaryContactNo = "456" },
}.ToList()
},
new StudentDto
{
Id = "2",
StudentContacts = new[]
{
new StudentContact { ContactName = "Foo", PrimaryContactNo = "789" },
new StudentContact { ContactName = "Bar", PrimaryContactNo = "101112" },
}.ToList()
},
}.ToList();
var driverActivationResponse = mapper.Map<List<Student>>(studentDtos);
Console.WriteLine($"Contacts Count: {driverActivationResponse.Count}");
Console.ReadKey();
}
}
public class StudentDto
{
public string Id { get; set; }
public List<StudentContact> StudentContacts { get; set; }
public StudentDto()
{
if (StudentContacts == null) StudentContacts = new List<StudentContact>();
}
}
public class Student
{
public string Id { get; set; }
public List<StudentContact> StudentContacts { get; set; }
public Student()
{
if (StudentContacts == null) StudentContacts = new List<StudentContact>();
}
}
public class StudentContact
{
public string ContactName { get; set; }
public string PrimaryContactNo { get; set; }
}
}

Unable to perform a not-in

I have a two objects, one AnotherList that contains an array of ints and the other MyFolder that contains an array of objects FolderItem that contains an array of objects ItemKeyword that have two strings (in a key-value-pair style).
I want to return a List<FolderItem> from MyFolder that are not referenced in the AnotherList. I can get a list of items that are in the list and have included the Linq for that at the bottom.
I have been fighting with .Contains and .Except extensions all day but keep getting errors. I'm hoping that this is easy for someone.
This is a case where code speaks a thousand words so here it is.
The Linq query at the end returns only one FolderItem at the moment folderItemID=25.
I need it to return all the FolderItems folderItemID=26,27,28 instead.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
namespace temp
{
class MyFolder
{
public FolderItem[] items { get; set; }
}
class FolderItem
{
public int folderItemID { get; set; }
public ItemKeyword[] keywords { get; set; }
}
class ItemKeyword
{
public string key { get; set; }
public string value { get; set; }
}
class AnotherList
{
public AnotherListItem[] items { get; set; }
}
class AnotherListItem
{
public int dataID { get; set; }
}
public class TestingClass
{
public static void mainApp()
{
AnotherList List1 = new AnotherList()
{
items = new AnotherListItem[]{
new AnotherListItem(){dataID=1},
new AnotherListItem(){dataID=2},
new AnotherListItem(){dataID=3}
}};
MyFolder List2 = new MyFolder()
{
items = new FolderItem[]
{
new FolderItem()
{
folderItemID=25, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="1"},
new ItemKeyword(){key="description", value="some text"},
}
},
new FolderItem()
{
folderItemID=26, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="4"},
new ItemKeyword(){key="description", value="some other text"},
}
},
new FolderItem()
{
folderItemID=27, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="9"},
new ItemKeyword(){key="description", value="even more other text"},
}
},
new FolderItem()
{
folderItemID=28, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="12"},
new ItemKeyword(){key="description", value="3"},
}
}
}};
List<FolderItem> res = (from someItems in List2.items
from itemKeywords in someItems.keywords
join otherItems in List1.items on itemKeywords.value equals otherItems.dataID.ToString()
where itemKeywords.key == "dataID"
select someItems).ToList<FolderItem>();
}
}
}
First grab all of the IDs that we don't want and stick them into a set for fast searching:
var badIDs = new HashSet<int>(List1.items.Select(item => item.dataID));
Then get all of the folders where they are not contained in that set:
var goodFolders = List2.items.Where(folder =>
!badIDs.Contains(folder.folderItemID));
Try using the Any extension method. You can confidently copy and paste the code below since it is meant to work with the code you provided...
List<FolderItem> res = List2.items.Where(x => !List1.items.Any(y => x.keywords.FirstOrDefault(z => z.key == "dataID").value == y.dataID.ToString())).ToList();
var res = List2.items.Where(fi => !List1.items.Any(al =>
al.dataID.ToString() == fi.keywords.Single(k => k.key == "dataID").value));
Assuming a FolderItem only has one ItemKeyword with key="dataID".

Categories

Resources