Suppose I have a List of Person (which is a class). It contains about 20 field (Name, Surname, Age, DateOfBirthdate, and so on). So I got this list:
var listOfPersons= MyContext.Persons.Cast<Person>();
Now, I need to iterate through this List, and for each Person adding a new field (which it is not present in the class), called, let's say, CurrentDateTime.
I could create a new object, with the new field, and "copy & paste" values from Person to the new Class. Somethings like:
PersonNew newPerson = new PersonNew("Name", "Surname", "Age", "DateOfBirthdate", ... "CurrentDateTime");
But this is very bad if in the future I change the Person class. So, is there a strategy to "extending Person" with a new field? That takes the Person instance (whatever it is) and adds the new field?
You can create some static method that create PersonNew from Person using Automapper.
public class PersonNew : Person
{
public static PersonNew CreateFromPerson(Person person, DateTime currentDateTime)
{
var newPerson = Mapper.Map<PersonNew>(person);
newPerson.CurrentDateTime = currentDateTime;
}
}
I think that the solution you described works fine. If you want to keep track of each person's birthday without extending the Person class, you might use a Dictionary object
var listOfPersons = MyContext.Perons.Cast<Person>();
Dictionary<Person, DateTime> birthdays = new Dictionary<Person, DateTime>
foreach(Person person in listOfPersons)
{
birthdays.Add(person, getBirthday(person);
}
One solution is to make your class partial, and add your field in another partial definition of your class:
public partial class Person
{
public string Name { get; set; }
public string FirstName { get; set; }
...
}
...
public partial class Person
{
public DateTime CurrentDateTime { get; set; }
}
...
var listOfPersons = MyContext.Persons.Cast<Person>();
foreach (var person in listOfPersons)
{
person.CurrentDateTime = ....
}
Do note that you will use the same instance of your class.
First I would suggest using extension methods for projecting collections instead of iterating. Like that:
var newCollection = oldCollection.Select(entity => MakeNewType(entity))
Second, it's not completely clear what you mean by "extending Person" with a new field. Here are the couple of ways you can accomplish that.
1) Make another class with the new field and map it to the old one. This is a common scenario for asp.net mvc application where you map models to the appropriate viewmodels. Automapper is useful for these types of scenario (see Sławomir Rosiek anwser)
2) Take advantage of dlr in c# 4+. Yuo will lose the intellisense for dynamic objects, but they canned be passed around functions
var newPeople = people.Select(p =>
{
dynamic expando = new ExpandoObject();
expando.Id = p.Id;
expando.FirtName = p.FirtName;
/* ... */
expando.CurrentDateTime = DateTime.Now;
return expando;
});
3) Use Anonymous types. Anonymous types cannot be passed to another functions, so this approach is useful when you need to quickly project data inside a single method and calculate some result
var newPeople = people.Select(p => new
{
Id = p.Id,
FirtName = p.FirtName,
/* ... */
CurrentDateTime = DateTime.Now
});
in both cases you can now access newly "created" property:
foreach(var p in newPeople)
{
Console.WriteLine("CurrentDateTime: {0}", p.CurrentDateTime);
}
4) If you really need to create a fully featured .net class at runtime you can use Reflection.Emit. This scenario is typically used to create dynamic proxies - subclasses which implement some functionality only known at runtime. Entity framework does this.
Related
I have a list of static methods that all essentially do the same thing, just on different tables/ entity classes:
public static List<FormFieldHistoryViewModel> GetTextLabelHistory(Guid entryId, int? formFieldId)
{
List<FormFieldHistoryViewModel> history = new List<FormFieldHistoryViewModel>();
List<dbo_FormFieldsFileValues_CT> fields = new List<dbo_FormFieldsFileValues_CT>();
using (var ctx = new Entities())
{
fields = ctx.dbo_FormFieldsFileValues_CT.Where(f => f.FormFieldsID == formFieldId && f.EntryID == entryId).ToList();
}
foreach (var row in fields)
{
var ffhvm = new FormFieldHistoryViewModel();
ffhvm.DateEdited = row.DateEdited;
ffhvm.EditedBy = row.EditedBy;
ffhvm.Value = row.FileName;
history.Add(ffhvm);
}
return history;
}
Instead of having one method for each table/ entity object, I'd like to just pass a reference to that class as an argument to be used at every place where you see edmxobject. How can I achieve this?
public static List<FormFieldHistoryViewModel> GetTextLabelHistory(Guid entryId, int? formFieldId, type edmxobject)
{
List<FormFieldHistoryViewModel> history = new List<FormFieldHistoryViewModel>();
List<edmxobject> fields = new List<edmxobject>();
using (var ctx = new Entities())
{
fields = ctx.edmxobject.Where(f => f.FormFieldsID == formFieldId && f.EntryID == entryId).ToList();
}
foreach (var row in fields)
{
var ffhvm = new FormFieldHistoryViewModel();
ffhvm.DateEdited = row.DateEdited;
ffhvm.EditedBy = row.EditedBy;
ffhvm.Value = row.FileName;
history.Add(ffhvm);
}
return history;
}
}
You can pass in the type parameter using generics via T.
GetTextLabelHistory<T>(Guid entryId, int? formFieldId) where T : {constraint}
In order to operate on your data context using this type, you can use the Set method of DbContext
myDbContext.Set<T>().SomeOperation()
DbContext.Set()
Generic Constraints
To get something like this to work nice and tidy you will need a base interface for your Edited* fields. Something like:
public interface IEditable
{
DateTime DateEdited { get; }
string EditedBy { get; } // Assuming it stores a name.
string FileName { get; }
}
Then each supported class inherit this interface. The method would change to:
public List<FormFieldHistoryViewModel> GetTextLabelHistory<T>(Guid entryId, int? formFieldId) where T : class, IEditable
Then your query to extract common fields from entities would be:
using (var ctx = new Entities())
{
fields = ctx.Set<T>()
.Where(f => f.FormFieldsID == formFieldId && f.EntryID == entryId)
.Select(f => new FormFieldHistoryViewModel
{
DateEdited = f.DateEdited,
EditedBy = f.EditedBy,
Filename = f.Filename
}).ToList();
return fields;
}
The issue here though is likely going to be filtering, as this assumes that every table is going to have EntryId and FormFieldId which I assume may not be the case given your example was for a table FormFieldsFileValues.
If you want to do something similar for completely dissimilar entities, the IEditable can help expose the common fields, but you'll probably be out of luck actually querying the appropriate records within the method itself. The same goes for if you have different desired output view models. Again, your example had it returning a view model that had a FileName which aligns with FormFieldFileValues, but this won't suit cases where you want to return different view models.
Generic methods are suitable when the implementation across all supported classes is identical, not just similar. The output of a generic method must either be a value, a single common type, or a generic class associated with the applicable type. We can handle filtering via different sources (Key names, criteria etc.) by designing the method to accept an IQueryable<T> rather than querying inside the method, but this still requires a singular output class applicable across all implementations. For example:
public List<HistoryViewModel> GetHistory<T>(IQueryable<T> query) where T : class, IEditable
{
string sourceType = typeof(T).Name;
return query.Select(f => new HistoryViewModel
{
SourceType = sourceType,
SourceId = f.Id,
DateEdited = f.DateEdited,
EditedBy = f.EditedBy,
}).ToList();
}
Where the IEditable exposes an Id column rather than class specific details, and it is up to the caller to build a query for what to get history view models for.
If you do want different specific history view models to pair up with different unrelated source entities then a Generic implementation likely isn't up to the task.
Suppose I have a DbSet like so:
DbSet<Teacher>
And a Teacher inherits from a Person (not part of the EF generated classes).
public partial class Teacher: Person
{
}
And I have a list of DbSets like so
var tableList = new List<Type>() { typeof(DbSet<Teacher>), typeof(DbSet<Student>), ... };
Then I want to create a generic function that does the same thing for each of the tables in the list.
How do I do something like the following if I know that all the tables in the list can inherit from the same Person type:
foreach(var tableType in tableList)
{
var table = (DbSet<Person>)Activator.CreateInstance(tableType);
var existing = table.Where(x => x.Name == "whatever");
if (!existing.Any())
{
table.Add(new Person{ Name = "Whatever" });
}
...
The problem is that EF doesn't know which table in the database I want to talk to. How do I tell it that 'in this loop I want you to save the new person to the Student table, in this loop I want you to save to the Teacher table, etc?
I've tried initialising the table like so but neither are useful:
var table = (DbSet<dynamic>)Activator.CreateInstance(tableType);
var table = (DbSet<tableType>)Activator.CreateInstance(tableType);
Note: I know I could've made loads of separate very similar functions for each table type but I've made the above example simple to make the problem easier to understand, I'm not actually saving different types of people in a loop based on whether their name exists. Any ideas? Thanks!
Since there are so many generic methods involved, you would be better off writing your own generic method, then use reflection to call it.
public void ProcessGeneric<T> where T:Person, new()
{
// Perhaps something like;
var dbSet = db.Set<T>();
if (!dbSet.Any(p => p.Name == ...))
dbSet.Add(new T(){ ... });
}
public void Process(Type t)
=> this.GetType()
.GetMethod(nameof(ProcessGeneric))
.MakeGenericMethod(t)
.Invoke(this, new object[] {});
I am trying to write some code in Linq with lambda.This is my first code using lambda and i am facing an issue while updating Record.
My code is:
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias,
mfr => mfr.RPT_ID,
nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= mfr.NOTIF_ID,
RecipAdd=nr.NOTIF_RECIP_ADDR
});
foreach(var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.NotifId = "Changedxyz";
//db.SubmitChanges();
}
}
}
I am getting Error in repljoinmf_data.NotifId = "Changedxyz";
Error says: Error 2 Property or indexer 'AnonymousType#3.NotifId' cannot be assigned to -- it is read only
Can someone please help me in this.I think it is because I am using var which is anonymous but how to solve the problem.Any help is appreciated.
Thanks
As the error suggests, anonymous class instances cannot be modified once they have been projected.
Although you could switch to a strong typed class, and then reassign the member properties, however, you have an opportunity to project the desired result in the preceding LINQ statement into the same anonymous class:
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new // Anon Class projection
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= "Changedxyz", // *** No need to mutate this afterwards
RecipAdd=nr.NOTIF_RECIP_ADDR
});
Edit, Update isn't trivial assignment, suggested alternatives
Option #1 : Strongly typed Class with mutation after projection
Add a new class (I've guessed some types)
public class MyPoco
{
public int ReportId {get; set;}
public string Reportversion {get; set;}
public byte[] ReportBytes {get; set;}
public DateTime ReportDate {get; set;}
public int NotifId {get; set;}
public string RecipAdd {get; set;}
}
Which you can then project into (just specify the class name instead of anonymous):
(mfr, nr) => new MyPoco // Not anonymous
{
ReportId=mfr.RPT_ID,
...
And then do modification afterwards:
foreach(var repljoinmf_data in repljoinmf)
{
repljoinmf_data.NotifId = "SomeNewValue"
Option #2 - Create a method (or Func) which does the complex logic
Since you seem to have already materialized all the data, you are free to use complex functions in the property projections. Any of the available local variables (closure) are available to pass to thus function, as are the join lambda parameters (mfr, nr)
So for example, write a function to calculate your NotifId = "Changedxyz" replacement:
private string DoIntensiveLogic(mainframe_replication mfr, NOTIF_RECIP nr)
{
// Do Stuff
}
Which you can then use in your original anonymous projection:
(mfr, nr) => new // Anon Class projection
{
ReportId=mfr.RPT_ID,
Reportversion=mfr.RPT_VERS,
ReportBytes= mfr.RPT_BYTES.ToString(),
ReportDate=mfr.REPL_DTM.ToString(),
NotifId= DoIntensiveLogic(mfr, nr), // Call the function each row
RecipAdd=nr.NOTIF_RECIP_ADDR
});
Anonymous types are immutable and hence created cannot be changed you have to create a new type.
To solve your issue you have to create your own type and avoid the use of anonymous type when a future update is needed.
your type may look like this
public class ReportInfo
{
public int Id{get; set;}
//the same thing for others properties
}
and your query will look like this
new ReportInfo() {
Id = mfr.RPT_ID,
Reportversion = mfr.RPT_VERS,
ReportBytes = mfr.RPT_BYTES.ToString(),
ReportDate = mfr.REPL_DTM.ToString(),
NotifId = mfr.NOTIF_ID,
RecipAdd = nr.NOTIF_RECIP_ADDR
})
than you can update easily your property
foreach(var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.NotifId = "Changedxyz";
//db.SubmitChanges();
}
More about anonymous Types
what the compiler is actually doing. When you write a line of code like this:
var o = new { property1 = expression1, ..., propertyN = expressionN };
the compiler infers the type of each expression, creates private fields of these inferred types, creates
public read-only properties for each of the fields, and creates a constructor that accepts all these
expressions. The constructor’s code initializes the private read-only fields from the expression results
passed in to it. In addition, the compiler overrides Object’s Equals, GetHashCode, and ToString
methods and generates code inside all these methods.
if you want to change 'NotifId' later, you can find a record by id and change the property.
Example:
var alias = mainframe_replication_alias.SingleOrDefault(mfr => mfr.NOTIF_ID == repljoinmf_data.NotifId);
if(alias != null)
alias.NOTIF_ID = "Changedxyz";
I am running into the "Lazy IO Problem" in Linq and I haven't found a solution that I'm happy with
Setting up the problem
Let say we have SQL tables that looks like
create table Person (
id int primary key not null,
name text not null,
)
create table Dog (
name text primary key not null,
ownerid text primary key not null references Person(name)
)
And in C# we want to use LINQ and Entity Framework to deal with this. Entity Framework classes are defined as partial so we can extend them to add a .Get(string) method and this makes for very clean code.
public partial class Dog
{
public static Dog Get(string dogname)
{
using (var db = new MyDataContext())
{
// LINQ is lazy and doesn't load the referenced Person
return db.Dogs.Single(d => d.name == dogname);
}
}
}
Where the problem happens
Now we attempt to use the Dog object for something
public string DogJson(string dogname)
{
var dog = Dog.Get(dogname);
return JsonConvert.SerializeObject(dog);
}
Since our instance dog contains dog.Owner because of the foreign key, JsonConvert will of course attempt to include it in the json string. But since the DataContext is disposed and LINQ is lazy, an ObjectDisposedException is of course raised because dog.Person had not been evaluated when we disposed the DataContext.
In this case, we don't care about the Owner object at all, we just want to serialize the Dog to json. What is the best way to do that without?
My solution
I have a solution, but I don't particularly like it. Using projection into an anonamous object and casting back to Dog, because we are not allowed to explicitly construct a Dog in the query.
public static Dog Get(string dogname)
{
using (var db = new MyDataContext())
{
var tmpdog = db.Dogs.Where(d => d.name == dogname)
.Select(d => new { name = d.name, ownerid = d.ownerid}).Single();
return new Dog() { name = tmpdog.name, ownerid = tmpdog.ownerid};
}
}
I don't like this solution because it doesn't scale well. This example only has two properties and this gets quickly out of hand. LINQ usually makes for very elegant code and this is not elegant at all. It's also prone to programmer
It sort of feels like I am taking the wrong approach here.
I have had this problem before too, but luckily entity framework provides an easy way around it. You can disable the lazy loading and creation of a dynamic proxy before you query. This will allow the json serializer to run without exception.
public static Dog Get(string dogname)
{
using (var db = new MyDataContext())
{
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
return db.Dogs.Single(d => d.name == dogname);
}
}
The real issue is that your caller should dictate the lifetime of the DbContext, not the callee, since the DogJson method is defining the unit of work. Ideally you should be passing a DbContext instance into the static Get method.
So, rather, your Get code should look more like this:
public static Dog Get(string dogname, MyDataContext db)
{
var result = db.Dogs.SingleOrDefault(d => d.name == dogname);
return result;
}
Then, you can do all of the DTO modifications in your caller, since that's really your unit of work:
public string DogJson(string dogname)
{
using (var db = new MyDataContext())
{
var dog = Dog.Get(dogname, db);
var dogDTO = new Dog { name = dog.name, ownerid = dog.ownerid };
return JsonConvert.SerializeObject(dogDTO);
}
}
See this question about ignoring attributes when serializing objects in Newtonsoft, which I believe is the library that contains the JsonConvert.SerializeObject function.
To summarize the most popular answer is to add the [JsonIgnore] attribute to those fields you do not want to be serialized. In your case, that is Owner so the code would be:
[JsonIgnore]
public Person Owner{ get; set; }
The original poster ended up using virtual properties as noted in their own answer.
Hello stackoverflow community!
Let's start!
I have one small class Person:
class Person
{
public string name { get; set; }
}
Аnd it has a descendant Employee:
class Employee : Person
{
public int salary { get; set; }
}
And second descendant is Guest:
class Guest: Person
{
public int id { get; set; }
}
Ok! looks good :)
Now I want to display a list of all employees OR guests in a single control ListView
I made a class (it really necessary) for list management PeopleList:
class PeopleList
{
public List<Person> People { get; set; }
...
public void LoadListFromFile()
{
// Load logic
this.People = new List<?>(source);
}
}
Do you see this question mark? No? Look at the code again!
How to create an instance of List that I can use my class something like this:
// This instance with the list of Person objects
PeopleList list = new PeopleList();
foreach (Employee e in list.People)
{
Debug.WriteLine(e.salary.toString());
}
// This instance with the list of Guest objects
PeopleList list = new PeopleList();
foreach (Guest g in list.People)
{
Debug.WriteLine(g.id.toString());
}
P.S. I'm new in c# and I think that I have a problem in architecture. And maybe you point me to the pattern solves my problem. I really need your help! Thank you!
I think you're after OfType, in the System.Linq library:
foreach (Employee e in personList.OfType<Employee>())
{
Debug.WriteLine(e.salary.toString());
}
foreach (Guest g in personList.OfType<Guest>())
{
Debug.WriteLine(g.id.toString());
}
The only field in Person that is shared with all of the decedents is the field 'name', therefore, if you are casting each item in your list to Person you will only have access to 'name'.
You have a few options to solve this issue. 1) you could move all of the common fields into the base class, but this is probably not want since it defeats the point of an object hierarchy, or 2) you can type check, using the "Is" keyword, each person in the list so see what type of person it is and then cast that Person to the appropriate decedent class before you operate on it.
For example:
foreach (Person p in list.People)
{
if(p is Employee)
{
Debug.WriteLine(((Employee)p).salary.toString());
}
if(p is Guest)
{
Debug.WriteLine(((Guest)p).Id.toString());
}
}
Here is an alternate more clear way of casting
foreach (Person p in list.People)
{
if(p is Employee)
{
Employee employee = p as Employee;
Debug.WriteLine(employee.salary.toString());
}
if(p is Guest)
{
Guest guest = p as Guest;
Debug.WriteLine(guest.Id.toString());
}
}
Additionally you can learn more about type checking using the "is" keyword here.
Also just for clarity, since it might not be obvious, some others have suggested that you use OfType in linq but this more of a way to filter like object from a list of mixed objects as opposed to actually type checking each one.
Enjoy!
As the comments are saying, you can do the following;
public void LoadListFromFile()
{
// Load logic
this.People = new List<Person>(source);
}
And then, cast where appropriate;
foreach (Person e in list.People.Where(p => p.GetType() == typeof(Employee)))
{
Debug.WriteLine(((Employee)e).salary.toString());
}
I think in your particular example, the inheritance structure is not adding much benefit, but I digress.
In your example, the easiest solution would be to override the ToString method in each one of your classes.
Having to know the exact type of the object before hand before you run some sort of calculation or display puts the onus of that calculation onto the calling code, if you make a 3rd type, you would have to update all possible references, giving you a maintenance nightmare.
The feel the logic of how to represent itself should be the responsibility (in your example) of the object itself.
This is what overriding ToString gives you, the responsibility of representing itself is then given to the thing that knows best (the object you're asking).