How to make CRUD m:m relationship c# - c#

How to make CRUD relationship m:m in my model?
Example:
My tables
People (PeopleId, Name)
Thing (ThingId, Name)
PeopleHasThing (PeopleId, ThingId)
My Model
PeopleModel.cs:
public int PeopleId { get; set; }
public string Name
{
get { return _name; }
set
{
if(value == _name) return;
_name = value;
OnPropertyChanged("Name");
}
}
public List<ThingModel> HasThing
{
get { return _hasThing; }
set
{
if(value == _hasThing) return;
_hasThing= value;
OnPropertyChanged("HasThing");
}
}
public static int Insert(PeopleModel m)
{
using (_context = new myDataContext())
{
var d = new People
{
Name = m.Name
Thing = // I don't know how to end this line
};
_context.People.InsertOnSubmit(d);
_context.SubmitChanges();
return d.PeopleId;
}
}
// I don't know how to update or retrieve this from the database
public static void Update(PeopleModel m);
public static void ListAll();
// With this I dont have problem! :P
public static void Delete(int peopleId);
PeopleHasThingModel.cs
public int PeopleId { get; set; }
public int ThingId { get; set; }
ThingModel.cs
public int ThingId { get; set; }
public string Name
{
get { return _name; }
set
{
if(value == _name) return;
_name = value;
OnPropertyChanged("Name");
}
}
public bool IsMarked
{
get { return _isMarked; }
set
{
if(value == _isMarked) return;
_isMarked= value;
OnPropertyChanged("IsMarked");
}
}
Thing is a list in my form are a checkbox list populate from thing table.
Example
I have 3 records in the things table:
1, "house"
2, "dog"
3, "car"
I need to save a new people and her things:
People:
1, "ruben"
PeopleHasThing:
1, 1 -- ruben has house
1, 3 -- ruben has car
Early approach
PeopleModel.cs
public static int Insert(PeopleModel m)
{
using (_context = new myDataContext())
{
var people = new People
{
Name = m.Name
};
// Create the PeopleHasThing record
m.HasThing.ForEach((e) =>
{
people.PeopleHasThing.Add(new PeopleHasThing
{
ThingId = e.ThingId,
People = people
});
});
_context.People.InsertOnSubmit(people);
_context.SubmitChanges();
return people.PeopleId;
}
}
// The following method works!
// I've tried but I have my doubts about deleting records
public static void Update(PeopleModel p)
{
using (_context = new myDataContext())
{
var result = (from r in _context.People
where r.PeopleId == p.PeopleId
select r).SingleOrDefault();
if (null == result) return;
result.Name = p.Name;
//Delete all PeopleHasThings with result.PeopleId ...
EntitySet<PeopleHasThing> set = new EntitySet<PeopleHasThing>();
m.HasThing.ForEach(e =>
{
if (e.IsMarked)
{
set.Add(new PeopleHasThing
{
ThingId = e.ThingId,
People = result
});
}
});
result.PeopleHasThing = set;
_context.SubmitChanges();
}
}

Your 3 models would look like this:
class PeopleModel {
public int PeopleID { get; set; }
public string Name { get; set; }
/* .. additional fields or values .. */
}
class ThingsModel {
public int ThingsID { get; set; }
public string Name { get; set; }
/* .. additional fields or values .. */
}
class PeopleHasThing {
public int PersonID { get; set; }
public int ThingsID { get; set; }
}
You can approach this with the 3 table model by housing only people related fields in the People table & only thing related fields in the Things table.
Then, you would house all of your relationships in the PeopleHasThing table with as many rows as needed.
As you create/edit People & Things, you need to know the ID # to build your relationships
PeopleModel myPerson = new PeopleModel();
myPerson.PeopleID // ID of Person
ThingsModel myThing = new ThingsModel();
myThings.ThingsID // ID of Thing
PeopleHasThings relationship = new PeopleHasThings();
relationship.PeopleID = myPerson.PeopleID;
relationship.ThingsID = myThings.ThingsID;
Example
People:
1, "ruben"
2, "joe"
Things:
1, "house"
2, "dog"
3, "car"
PeopleHasThing:
1, 1 -- ruben has house
1, 3 -- ruben has car
2, 1 -- joe has house

Related

c# getting suitable field from database by languages in linq connect model

I am using dotConnect for MySQL product of Devart. MySQL database structure likes this:
I am getting data like this:
public int user_id { get; set; } = 2;
public string lang { get; set; } = "en"; // Depending on the situation, it may also be "tr".
private readonly mainDataContext _db = new();
var cats = _db.categories.Where(s => s.u_id == user_id);
foreach (var cat in cats)
{
MessageBox.Show(cat.name_en);
}
In the MessageBox.Show I can not use cat.name + "_" + lang like PHP. I don't know how to get over this problem.
In nutshell, you can use this:
cat.GetType().GetProperty("name_" + lang).GetValue(cat,null))
But it's better to call a method to get value:
static public T getval<T>(Object obj, string field)
{
return (T)obj.GetType().GetProperty(field).GetValue(obj, null);
}
Here is a full example:
using System;
namespace Example
{
public class user
{
public int user_id { get; set; } = 2;
public string name_en { get; set; }
public string name_tr { get; set; }
}
class Program
{
static public T getval<T>(Object obj, string field)
{
return (T)obj.GetType().GetProperty(field).GetValue(obj, null);
}
static void Main(string[] args)
{
List<user> u = new List<user>();
u.Add(new user { user_id = 1, name_en = "Foods", name_tr = "name_tr value 1" });
u.Add(new user { user_id = 2, name_en = "Pizza", name_tr = "name_tr value 2" });
u.Add(new user { user_id = 2, name_en = "Other", name_tr = "name_tr vale 3" });
var lang = "en";
var cats = u.Where(s => s.user_id == 2);
foreach (var cat in cats)
{
Console.WriteLine(getval<string>(cat,"name_"+lang));
}
return;
}
}
}

Linq query for the Multi list in singe out put

i have table looks like below
ID | Reason | PrID
-----------------
1 abc null
2 dhe null
3 aerc 1
4 dwes 2
5 adfje 1
i have class
public class Reason
{
public int Id { get; set; }
public string Reson{ get; set; }
public List<SecondryReason> SecReason{ get; set; }
public int? PrimaryId { get; set; }
}
public class SecondryReason
{
public int Id { get; set; }
public string Reason { get; set; }
public int PrimaryReasonId { get; set; }
}
I want this to be displayed in hierarchy level
if the prid is Null need to treat this as the parent remaining all child
i am trying Linq and unable to achieve this
Suggest me how to do this in an easy way in linq
So: You have a list/enumerable of type , whereof the SecReason List property is null. Then, using linq you want a list, were the only the "root" reasons remain, but the Sub-reasons got put in the lists, but as type SecondaryReason?
If so, I found this way to do it (linq and foreach):
static IEnumerable<Reason> GetReasonsGrouped(List<Reason> reasons)
{
var result = reasons.Where(x => x.PrimaryId == null);
foreach (var item in result)
{
item.SecReason = reasons.Where(x => x.PrimaryId == item.Id)
.Select(x => new SecondryReason()
{ Id = x.Id,
ReasonName = x.ReasonName,
PrimaryReasonId = item.Id
})
.ToList();
}
return result;
}
Or just linq, but harder to read:
var result = reasons.Where(x => x.PrimaryId == null)
.Select(x =>
{
x.SecReason = reasons.Where(r => x.PrimaryId == x.Id)
.Select(r => new SecondryReason()
{
Id = r.Id,
ReasonName = x.ReasonName,
PrimaryReasonId = x.Id
})
.ToList();
return x;
});
Not sure if linq will be the best solution, here is my proposed changes and method to get an Hierarchy type:
public class Reason
{
public int Id { get; set; }
public string Reson { get; set; }
public List<Reason> SecReason { get; set; }
public int? PrimaryId { get; set; }
//Adds child to this reason object or any of its children/grandchildren/... identified by primaryId
public bool addChild(int primaryId, Reason newChildNode)
{
if (Id.Equals(primaryId))
{
addChild(newChildNode);
return true;
}
else
{
if (SecReason != null)
{
foreach (Reason child in SecReason)
{
if (child.addChild(primaryId, newChildNode))
return true;
}
}
}
return false;
}
public void addChild(Reason child)
{
if (SecReason == null) SecReason = new List<Reason>();
SecReason.Add(child);
}
}
private List<Reason> GetReasonsHierarchy(List<Reason> reasons)
{
List<Reason> reasonsHierarchy = new List<Reason>();
foreach (Reason r in reasons)
{
bool parentFound = false;
if (r.PrimaryId != null)
{
foreach (Reason parent in reasonsHierarchy)
{
parentFound = parent.addChild(r.PrimaryId.Value, r);
if (parentFound) break;
}
}
if (!parentFound) reasonsHierarchy.Add(r);
}
return reasonsHierarchy;
}

Model one to many in RavenDb for better performance

I'm approaching to document database and I'm little bit confused how to map documents relationship, in a situation as follow
public class Person
{
public Person()
{
}
public int Id { get; set; }
public string Name { get;set;}
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public Car() { }
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set;}
}
A person has one or more cars for example in this way I can query the db as follow
public Car Get(int id)
{
Car car = null;
using (IDocumentSession session = store.OpenSession())
{
car = session.Include<Car, Person>(x => x.PersonId).Load<Car>(id);
bool isLoaded = session.Advanced.IsLoaded("people/" + car.PersonId); // true!
}
return car;
}
and it's everything ok, the client makes just one request, but if I have a person and I want to show all his cars how can I query the db to do just a request?
I think tha I must modify the model putting a List<int> Cars in Person for reference his cars.
Note that I don't want to embed Cars in the Person document because Cars can be referenced from others document.
Thanks.
You can do it like this:
using (IDocumentSession session = store.OpenSession())
{
var carsForOne = session.Query<Car>()
.Include(x=>x.PersonId)
.Where(x=>x.PersonId == "people/1")
.ToList();
var person = session.Load<Person>("people/1");
}
This make just a single db request.
You can index the Cars collection and load all the cars from the index.
The index would look like this:
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
The CarView class is identical to the Car class, but can be changed to better fit the indexing needs.
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
You'll need to execute the index before being able to use it:
new CarIndex().Execute(store);
Loading the cars for a certain person would look like this:
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForIndexing(store); // from RavenTestBase
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
If you want to load the person and their cars in a single database request, use lazy loading:
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Complete test (needs xunit and RavenDB.Tests.Helpers nugets):
using Raven.Client;
using Raven.Client.Indexes;
using Raven.Tests.Helpers;
using System;
using System.Linq;
using Xunit;
namespace SO41547501Answer
{
public class SO41547501 : RavenTestBase
{
[Fact]
public void SO41547501Test()
{
using (var server = GetNewServer())
using (var store = NewRemoteDocumentStore(ravenDbServer: server))
{
new CarIndex().Execute(store);
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForAllRequestsToComplete(server);
WaitForIndexing(store);
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
using (IDocumentSession session = store.OpenSession())
{
server.Server.ResetNumberOfRequests();
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Assert.Equal("A", personValue.Name); // person data loaded
Assert.Equal("A", resultsValue.First().Name); // cars data loaded
Assert.Equal(1, server.Server.NumberOfRequests); // only one request sent to the server
}
}
}
}
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
}

Cleanest Way To Map Entity To DTO With Linq Select?

I've been trying to come up with a clean and reusable way to map entities to their DTOs. Here is an example of what I've come up with and where I'm stuck.
Entities
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
// Other properties not included in DTO
}
public class Address
{
public int ID { get; set; }
public string City { get; set; }
// Other properties not included in DTO
}
DTOs
public class PersonDTO
{
public int ID { get; set; }
public string Name { get; set; }
public AddressDTO Address { get; set; }
}
public class AddressDTO
{
public int ID { get; set; }
public string City { get; set; }
}
Expressions
This is how I began to handle the mapping. I wanted a solution that wouldn't execute the query before mapping. I've been told that if you pass a Func<in, out> instead of Expression<Func<in, out>> that it will execute the query before mapping.
public static Expressions
{
public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = new AddressDTO()
{
ID = person.Address.ID,
City = person.Address.City
}
}
}
One issue with this is that I already have an expression that maps an Address to an AddressDTO so I have duplicated code. This will also break if person.Address is null. This gets messy very quick especially if I want to display other entities related to person in this same DTO. It becomes a birds nest of nested mappings.
I've tried the following but Linq doesn't know how to handle it.
public static Expressions
{
public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = Convert(person.Address)
}
public static AddressDTO Convert(Address source)
{
if (source == null) return null;
return new AddressDTO()
{
ID = source.ID,
City = source.City
}
}
}
Are there any elegant solutions that I'm missing?
If you want to create mappings manually then you can use Select on the collection in the following way:
Some test data:
var persons = new List<Person>
{
new Person() {ID = 1, Name = "name1", Address = new Address() {ID = 1, City = "city1"}},
new Person() {ID = 2, Name = "name2", Address = new Address() {ID = 2, City = "city2"}},
new Person() {ID = 3, Name = "name3", Address = new Address() {ID = 1, City = "city1"}}
};
Mapping methods:
public static PersonDTO ToPersonDTOMap(Person person)
{
return new PersonDTO()
{
ID = person.ID,
Name = person.Name,
Address = ToAddressDTOMap(person.Address)
};
}
public static AddressDTO ToAddressDTOMap(Address address)
{
return new AddressDTO()
{
ID = address.ID,
City = address.City
};
}
Actual usage:
var personsDTO = persons.Select(x => ToPersonDTOMap(x)).ToList();
Keep in mind that if this was a real query is would not get executed as long as it was IQueryable, it would be executed once you materialize it (using ToList() for example).
However, I would consider using some framework which could do it (the mappings) for you automatically (if your mapping are as simple as provided example(.
Just use AutoMapper.
Example:
Mapper.CreateMap<Address, AddressDTO>();
Mapper.CreateMap<Person, PersonDTO>();
Your query will execute when the mapping is performed but if there are fields in the entity that you're not interested use Project().To<> which is available both for NHibernate and EntityFramework. It will effectively do a select on the fields specified in the mapping configurations.
Automapper is the best way .
For me, I use this for simple objects only, but I don't recommend it
public static class ObjectMapper
{
public static T Map<T>(object objfrom, T objto)
{
var ToProperties = objto.GetType().GetProperties();
var FromProperties = objfrom.GetType().GetProperties();
ToProperties.ToList().ForEach(o =>
{
var fromp = FromProperties.FirstOrDefault(x => x.Name == o.Name && x.PropertyType == o.PropertyType);
if (fromp != null)
{
o.SetValue(objto, fromp.GetValue(objfrom));
}
});
return objto;
}
}
And I call it like that wherever I want
var myDTO= ObjectMapper.Map(MyObject, new MyObjectDTO());
You could either use AutoMapper or write extension methods like these:
public static class PersonMapper
{
public static PersonDTO ConvertToDTO(this Person person)
{
return new PersonDTO { ID = person.ID, Name = person.Name, Address = person.Address.ConvertToDTO() };
}
public static IEnumerable<PersonDTO> ConvertToDTO(this IEnumerable<Person> people)
{
return people.Select(person => person.ConvertToDTO());
}
}
public static class AddressMapper
{
public static AddressDTO ConvertToDTO(this Address address)
{
return new AddressDTO { ID = address.ID, City = address.City };
}
public static IEnumerable<AddressDTO> ConvertToDTO(this IEnumerable<Address> addresses)
{
return addresses.Select(address => address.ConvertToDTO());
}
}
You could then map a Person object to a PersonDTO object like this:
public class Program
{
static void Main(string[] args)
{
Person person = new Person { ID = 1, Name = "John", Address = new Address { ID = 1, City = "New Jersey" } };
PersonDTO personDTO = person.ConvertToDTO();
Console.WriteLine(personDTO.Name);
}
}
I see the way you want to do it. I can propose you this solution:
public class PersonDTO
{
public int ID { get; set; }
public string Name { get; set; }
public AddressDTO Address { get; set; }
public static Expression<Func<Entities.Person, PersonDTO>> PersonSelector
{
get
{
return person => new PersonDTO()
{
ID = x.Id,
Name = x.Name,
Address = x.Address
.Select(AddressDTO.AddressSelector)
};
}
}
}
public async Task<PersonDTO> GetPerson(int id)
{
var person = await _personRepository.Get(id, PersonDTO.PersonSelector);
return person;
}
public async Task<TResult> Get<TResult>(int id, Expression<Func<Person, TResult>> selector)
{
var result = await _context.Persons
.Where(x => x.Id == id)
.Select(selector)
.SingleOrDefaultAsync();
return result;
}

LINQ Query to Filter Items By Criteria From Multiple Lists

I'm having trouble conceptualizing something that should be fairly simple using LINQ. I have a collection that I want to narrow down, or filter, based on the id values of child objects.
My primary collection consists of a List of Spots. This is what a spot looks like:
public class Spot
{
public virtual int? ID { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string TheGood { get; set; }
public virtual string TheBad { get; set; }
public virtual IEnumerable<Season> Seasons { get; set; }
public virtual IEnumerable<PhotographyType> PhotographyTypes { get; set; }
}
I'm trying to filter the list of Spots by PhotographyType and Season. I have a list of ids for PhotographyTypes and Seasons, each in an int[] array. Those lists look like this:
criteria.PhotographyTypeIds //an int[]
criteria.SeasonIds //an int[]
I want to build a collection that only contains Spots with child objects (ids) matching those in the above lists. The goal of this functionality is filtering a set of photography spots by type and season and only displaying those that match. Any suggestions would be greatly appreciated.
Thanks everyone for the suggestions. I ended up solving the problem. It's not the best way I'm sure but it's working now. Because this is a search filter, there are a lot of conditions.
private List<Spot> FilterSpots(List<Spot> spots, SearchCriteriaModel criteria)
{
if (criteria.PhotographyTypeIds != null || criteria.SeasonIds != null)
{
List<Spot> filteredSpots = new List<Spot>();
if (criteria.PhotographyTypeIds != null)
{
foreach (int id in criteria.PhotographyTypeIds)
{
var matchingSpots = spots.Where(x => x.PhotographyTypes.Any(p => p.ID == id));
filteredSpots.AddRange(matchingSpots.ToList());
}
}
if (criteria.SeasonIds != null)
{
foreach (int id in criteria.SeasonIds)
{
if (filteredSpots.Count() > 0)
{
filteredSpots = filteredSpots.Where(x => x.Seasons.Any(p => p.ID == id)).ToList();
}
else
{
var matchingSpots = spots.Where(x => x.Seasons.Any(p => p.ID == id));
filteredSpots.AddRange(matchingSpots.ToList());
}
}
}
return filteredSpots;
}
else
{
return spots;
}
}
You have an array of IDs that has a Contains extension method that will return true when the ID is in the list. Combined with LINQ Where you'll get:
List<Spot> spots; // List of spots
int[] seasonIDs; // List of season IDs
var seasonSpots = from s in spots
where s.ID != null
where seasonIDs.Contains((int)s.ID)
select s;
You can then convert the returned IEnumerable<Spot> into a list if you want:
var seasonSpotsList = seasonSpots.ToList();
This may helps you:
List<Spot> spots = new List<Spot>();
Spot s1 = new Spot();
s1.Seasons = new List<Season>()
{ new Season() { ID = 1 },
new Season() { ID = 2 },
new Season() { ID = 3 }
};
s1.PhotographyTypes = new List<PhotographyType>()
{ new PhotographyType() { ID = 1 },
new PhotographyType() { ID = 2 }
};
Spot s2 = new Spot();
s2.Seasons = new List<Season>()
{ new Season() { ID = 3 },
new Season() { ID = 4 },
new Season() { ID = 5 }
};
s2.PhotographyTypes = new List<PhotographyType>()
{ new PhotographyType() { ID = 2 },
new PhotographyType() { ID = 3 }
};
List<int> PhotographyTypeIds = new List<int>() { 1, 2};
List<int> SeasonIds = new List<int>() { 1, 2, 3, 4 };
spots.Add(s1);
spots.Add(s2);
Then:
var result = spots
.Where(input => input.Seasons.All
(i => SeasonIds.Contains(i.ID))
&& input.PhotographyTypes.All
(j => PhotographyTypeIds.Contains(j.ID))
).ToList();
// it will return 1 value
Assuming:
public class Season
{
public int ID { get; set; }
//some codes
}
public class PhotographyType
{
public int ID { get; set; }
//some codes
}

Categories