I'm feeling a little led by MVC and Entity framework... so I need help
The problem is I have 2 types of model: Person, Sausage
A Person can be made without any relationships to a sausage, similarly
a Sausage can be made without any relationships to a person.
When you go to a Person, you can add sausages he has eaten.
A sausage can be eaten by many people.
I have created 3 SQL tables:
People
Sausages
Sausages_People (the relationship table which has 2 foreign keys relating to People and to Sausages tables)
I have also created 2 classes:
Person
Sausage
A Person can eat multiple sausages so I did this:
class Person
{
IEnumerable<Sausage> Sausages { get; set; }
}
But using my entity framework DbContext, I am confused at how to link this up to the database...
I am creating database tables first then coding classes (migrations are off)
class EFDbContext : DbContext
{
public DbSet<Sausage> Sausages { get; set; }
public DbSet<Person> People { get; set; }
// I guess I need a relationship table stated here too right? so:
public DbSet<Sausage_Person> Sausages_People { get; set; }
// Is this right?
}
That means I need a separate class:
class Sausage_Person
{
public int SausageID { get; set; }
public int PersonID { get; set; }
}
Does that mean after all this, I actually want my Person to have a property like this:
class Person
{
IEnumerable<Sausage_Person> Sausages { get; set; }
}
What's the usually technique for this?
When I now go to a Person and add a Sausage to him, do I just have to add a new repository method
AddSausagePersonRelation( int sausageID, int personID ){ ... }
Do I not need the IEnumerable?
you are pretty close...
but i personally would avoid the int constructors since iny,int is ambiguous... maybe try
AddSausagePersonRelation( Sausage s, Person p ){ ... }
i would not put any IEnumerable in Person for the sausages...
You do need the IEnumerable. The problem in your situation, I think, is that you are still thinking in terms of the database architecture and are including the intermediate table that links people and sausages in your object model. It is entirely unnecessary.
Let's say you are using a CodeFirst approach (I advice you to do so whenever the project makes it feasible). Then your thinking should go like this:
"Ok, so I have people and sausages. People can have 0 sausages and a sausage can be nobody's (it can be without an owner). So basically the linking infrastructure between them should be many-to-many with the possibility of no connections. What data structure do I need to represent this (it should be able to contain 0 or more references to the other class)? Well, IEnumerable/ICollection should do the trick."
Thus, you have the classes:
public class Person()
{
IEnumerable<Sausage> Sausages { get; set; }
public Person()
{
this.Sausages = new HashSet<Sausage>();
}
}
public class Sausage()
{
IEnumerable<Person> People { get; set; }
public Person()
{
this.People = new HashSet<People>();
}
}
If you are using CodeFirst as your approach, the table with the IDs that makes possible expressing the many-to-many relationship in terms of SQL Database design will be automatically generated by EntityFramework.
Edit:
As someone mentioned in the comments, a sausage can indeed be considered property of only one person (excluding more complicated situations like sharing, etc.). In this case, it is perfectly OK to have something like:
public class Person()
{
IEnumerable<Sausage> Sausages { get; set; }
public Person()
{
this.Sausages = new HashSet<Sausage>();
}
}
public class Sausage()
{
Person Person { get; set; }
}
Again, EntityFramework in case of CodeFirst will generate the tables you need in this situation. You, of course, can assume control over the exact details of that process by using CodeFirst Data Annotations or FluentAPI.
Use an ICollection so that you can add to it:
class Person
{
IEnumerable<Sausage_Person> Sausages { get; set; }
}
Make sure to initialize it in the constructor:
Sausages = new HashSet<Sausage_Person> = new HashSet<Sausage_Person>();
To Add a Sausage to a Person you could just Add it to Sausages or you could write a method like this:
public void AddExistingSausage{Sausage sausage}
{
var personSausage = new PersonSausage{PersonID = this.ID, SausageID = Sausage.ID};
this.Sausages.Add(personSausage);
}
However, the above method depends on the sausage parameter being an existing Sausage.
Related
Let's say I have an ObservableCollection<Person>.
Now, every student can have some sort of opinion on every other person. What would be the best way to code something like this, so that it's accessible from both objects?
I thought about something like this for a relations:
enum RelationPoint { Neutral, Like, Dislike, Love, Hate }
List<RelationPoint> relation;
How can I define something like this for every person?
You could create an object, which stores the opinion in an object, like this:
public class Opinion
{
public Person Destination
{
get;
set;
}
public Person Target
{
get;
set;
}
public RelationPoint RelationType
{
get;
set;
}
}
If you store them like this in a list, every person can have an opinion abount another pserson.
To figure out, which person has which optinion, you can simply find this out using linq:
var goodRelation = listOfOption.Where(item => item.RelationType == RelationPoint.Like && item.Destination = <<Some Person>>);
Now you know, which person the Destination likes.
One solution would be to make an object called "Relation" which contains 2 persons.
So you would have following classes:
public class Person
{
public String Name;
....
}
and a class "Relation:
public class Relation
{
private Person p1;
private Person p2;
private String opinion;
}
Now you could make sth. like this:
Person p = new Person ("John");
Person p2 = new Person ("David");
Relation r1 = new Relation(p, p2, "Neutral");
Just one of many solutions.
I was asked a question yesterday that is throwing me for a loop. I was asked to implement the interface IPeopleFinder:
public interface IPeopleFinder
{
IEnumerable<Person> GetByAge(List<Person> people, int age);
IEnumerable<Person> Find<TType>(Func<IEnumerable<TType>, bool> filter);
}
on this class:
public class People
{
public List<Student> Students { get; }
public List<Teacher> Teachers { get; }
}
The first function is simple, but the second function I do not understand what it is trying to do:
IEnumerable<Person> Find<TType>(Func<IEnumerable<TType>, bool> filter);
The IEnumerable<TType> in the Func is what I do not understand. If the signuture was:
IEnumerable<Person> Find<TType>(Func<TType, bool> filter);
it would be a simple matter of passing the filter to the IEnumerable<T>.Where() function.
Could someone please explain how filter function accepting an IEnumerable<T> and returning a bool would work? I'm starting to think it is a typo and should be Func<TType, bool>.
Clarification on restraints:
Classes are defined thus:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ushort Age { get; set; }
public Sex Sex { get; set; }
}
public class Student : Person
{
public Major Major { get; set; }
}
public class Teacher : Person
{
public Department Department { get; set; }
}
TType is restricted to be of type Person.
The way the question is written, once the Find method is implemented, it is to be used to find all Students majoring in a certain subject, and all Teachers belonging to a certain department.
Obviously the method should work for enumerations of enumerations such as
var l = new List<List<Student>>();
Now you can call myPeopleFinder.Find(x => x.Any()) which would return an enumeration of students.
A better example would be to filter those sub-lists from your enumeration that have a specific size:
myPeopleFinder.Find(x => x.Count() > 30)
EDIT: For a practical use-case imagine a school as a list of classes where every class itself has a list of Student and Teacher. Now you want to get all those classes that have more then a given amount (30 in my example) of Person (assuming that either Student and Teacher inherit from Person). Finally this method may flatten the resulting sub-lists into one single enumeration of type Person to get all the students and teachers within the overfull classes.
EDIT2: As you´re concerning to the properties of the persons instead of the list you should of course - as you´ve already assumed - use a Func<TType> with TType : Person. Seems like a type to me too.
I agree with your analysis and I wonder what kind of specification you got and from where.
The person who defined the IPeopleFinder interface should not only write code but also document it, at least in source code, better yet: describe the reason for the interface in a requirements document, define the context in a software architecture document and describe the detailed use in a design document.
As long as you only have the interface and no further description, just throw a NotImplementedException since it has not been defined that you should do something else.
I have a SP that returns list of Employees and a single row Department which should be consumed from EF code first.
I have the below object that needs to be filled,
public class EmployeeDetail
{
public IList<Employee> employeeslist { get;set; }
public int DeptID { get;set; }
public string DepartmentName { get;set; }
public int DeptStatusID { get;set; }
public decimal Expense { get;set; }
}
public partial class DBModel : DbContext
{
public ObjectResult<EmployeeDetail> PaymentBatchDetailsGet(int deptid)
{
return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<EmployeeDetail>
("GetEmployees #p0", deptid);
}
}
The SP is very simple which has 2 simple query listed below,
select * from Employee where DepartmentID = #deptid
select DepartmentName,DeptStatusID,Expense
FROM Department where DepartmentID = #deptid
All the properties in EmployeeDetail class is getting populated except employeeslist. Could you please help?
What makes you think that would work? As I understand it, the ExecuteStoreQuery method will only populate properties with primitive types (numbers, strings, etc.). See https://msdn.microsoft.com/en-us/library/ee358758(v=vs.110).aspx
Also, I'm not sure why you think it would work when the results are returned in two recordsets.
I'd love to think that this sort of thing could work, but I think it would be surprising if it did.
I think you'll need to split your SP into two parts, one that gets the top-level info, and another that gets the employees.
Is there in C# any hydrating technique allowing to transfer values from one struct/object to another struct/object if they have similar fields or based on certain strategy. I came from Zend Framework 2 world, and it provides the feature "Hydrator" which allows do exactly what I said above. So, I am wondering whether Asp.Net or C# provides something similar.
To make it clear, I want something like this:
struct UserInfo {
public string FirstName { get; set; };
public string LastName { get; set; };
public int Age { get; set; };
}
class UserUpdateModel {
public string FirstName { get; set; };
public string LastName { get; set; };
public int Age { get; set; };
}
...
//supposed UserUpdateModel model I is gotten from the action param
UserInfo info = new UserInfo();
Hydrator hydrator = new Hydrator(Hydrator.Properties);
hydrator.hydrate(info, model);
Now, "info" should be populated with values from "model"
Any help is appreciated.
Yes. AutoMapper. It is designed specifically for this. I personally prefer writing ViewModel constructor that takes an entity and copies the properties. I like the control and familiarity of good old C# code even if it takes a bit more effort.
Automapper should do the trick. You can use it as a nuget package.
Once you have your types and a reference to AutoMapper, you can create a map for the two types.
Mapper.CreateMap<UserUpdateModel, UserInfo>();
The type on the left is the source type, and the type on the right is the destination type. To perform a mapping, use the Map method.
UserInfo info = Mapper.Map<UserInfo>(userUpdateModel);
I have what seems to be a simple problem, but am unable to come up with a clean solution.
I have a two classes which looks like below
Class Person{
String name{get; set;}
int age{get; set;}
}
Class Alien{
String alienName{ get; set}
int alienAge{get; set;}
}
These classes are thirdparty classes that I have to use, have no control over. But at some point I would want to be able to construct a Alien object given a Person object and vice versa. I have only two properties in my example. In real life I may have upto 50 properties for both Alien and Person.
Alien is not a subset of Person and Person is not a subset of alien. Those are just two different objects. What do you guys think is the best way to transform these objects between each other. I don't want to laboriously write a copy method that takes in each property and sets its equivalent property in the other. Since the method names can be vastly different between those two classes, I don't think I might be able to use reflection either. Ideally am looking for something which would externalize the copy procedure so that if something changes in Alien or Person object in the future, I wouldn't have to change my logic.
Any suggestions?
Thanks
K
You might want to look at AutoMapper
Use Interfaces. If you have an Interface, certain properties that you must to be copied are already defined:
Interface ISubject
{
// properties
String name {get; set;}
int age {get; set;}
}
Class Person : ISubject
{
// contractors
public Person ()
{
...
}
public Person (ISubject subject)
{
name = subject.name;
age = subject.age;
}
...
}
Class Alien : ISubject
{
// contractors
public Alien ()
{
...
}
public Alien (ISubject subject)
{
name = subject.name;
age = subject.age;
}
...
}
and when you using:
var person = new Person();
...
ISubject subject = (ISubject) person;
var name = subject.name;
or
var person = new Person();
...
Alien subject = new Alien(person);
var name = alien.name;
You can try http://code.google.com/p/nutil/ , there is a class named BeanUtils, that have a method to copy properties.