IEnumerable<> instead of List<> goes well when reading objects - c#

Consider my following class Album:
public class Album
{
public int? Id { get; set; }
public string Name { get; set; }
public IEnumerable<Photo> Photos { get; set; }
public DateTime Registered { get; set; }
}
I have no troubles retrieving data out and populating my album and my photo collection.
However now I also want to 'Add' a Photo item into my Photos collection, 'Add' is not recognized as a valid method on Photos.
'System.Collections.Generic.IEnumerable'does not contain a
definition for 'Add' and no extension method 'Add' accepting a first
argument of type....
What should I do as a simple thing to get it to work with IEnumerable? I don't want to change my property to
public List<Photo> Photos { get; set;}
Do I really need to implement ICollection on my Album class?
public class Album : ICollection<Photo> { ... }

If you do not want to change the property type to something that allows addition (IList<Photo> or ICollection<Photo>) add a separate method for adding pictures, like this:
public void AddPhoto(Photo p) {
...
}
This would let you keep IEnumerable<Photo> as the type of your property, and also allow for validation of what the callers put in. For example, your code would be able to detect if a photo is too big or too small, and throw an exception. This would be a lot harder to do if you exposed IList<Photo>, because you would need to provide your own implementation that overrides Add.
You should also make the setter of your auto property private, or replace the auto property with a getter + a backing field.

Try making Photos a private List then create a standard property exposing it as an IEnumerable. Then add an "AddPhoto" method to your album object.
This way you allow album to control how it adds items to its internal collection.
public class Album
{
private List<Photo> _photos = new List<Photo>();
public IEnumerable<Photo> Photos { get { return _photos; } }
public void AddPhoto(Photo photo)
{
_photos.Add(photo);
}
}
*Edit This is a similar answer to dasblinkenlight, just with a more fleshed out code. I'll leave it here for now as it adds a little bit of clarification.

IEnumerable<T> does not allow sequence to be changed during enumeration. There is no other way but use another interface, such ICollection<T> or IList<T>.
So that the Photos will look like
public IList<Photo> Photos { get; set;}
// or
public ICollection<Photo> Photos { get; set;}
You can of course use actual classes and not interfaces, but usually interfaces give you more freedom.

Try:
myAlbum.Photos = myAlbum.Photos.Concat(newPhoto);
You need to add using System.Linq; on top of your file.

Related

What is best approach for data inheritation in elasticsearch?

I have an parent class and two child like these:
public class Parent {
public Guid Id { get; set; }
public string Name { get; set; }
}
public class FirstChild {
public string IdentityCode { get; set; }
}
public class OtherChild {
public string RegistrationCode { get; set; }
}
There is a question: Is it a good approach to store these two inherited classes in the same Index inside ElasticSearch?
I see there is a _type property that is added to my docs after they are stored in DB but it has always "doc" value.
I test this code to fill it but it seems it is not working this way.
await ElasticClient.IndexAsync<FirstChild>(child, m => m.Index(IndexName));
And Also, I found this question on SO for retrieving my entries from DB but it is outdated and the API is changed and no more accessible.
I want to know if it is a good approach to store sibling data in the same index how can I do this properly.
As of ES 6.0, it is not possible anymore to store multiple types inside the same index, i.e. the _type field you're referring to will always be either doc or _doc. In ES 8.0, the _type field will be removed altogether.
However, if it makes sense for your use case, you can still decide to store several types inside a single index using a custom type field that is present in your document.
You should strive to only store in the same index data that share the same (or very similar) mapping, which doesn't seem to be the case for Parent, FirstChild and SecondChild, but if you add a public string type property to your classes you can still do it.

How to display custom field type on data grid view? [C# / WinForms]

I have employee class, which has field of type ISalary (Interface). In data grid view, I want to display that salary, but what I get is empty field. Is it any possible way to display that "custom type field" in data grid view? invoking toString method would help, but I can't understand how to do that.
Here is how I am binding data:
employeeBindingSource.DataSource = employeesList;
All fields in that list, ofc is not null. And here is some of my class, which list I want to display:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int DepartmentId { get; set; }
// how to display this?
public ISalary Salary { get; set; }
...
}
I did some research and could not find any example on it. Or maybe was not trying hard enough.:/
Since you are using a interface as type of property, you can not override ToString method for that ISalary type without knowing the concrete type. So if you know a Salary class which implemented that interface and used instead of that interface at run-time, you can override ToString of that type.
But, in general it's not a good idea to rely on ToString of that concrete type, this way your program will be tightly relied on the concrete type and will loose its goal in using the interface.
Instead, you can use either of these options:
Use CellFormatting event to provide display value.
Use a DataGridViewComboBoxColumn which contains a List<Salary> but, set its display style property to nothing to not show dropdown button.
Use a readonly property in Employee class which return a known property of ISalary, like return this.Salary.SomeProperty;
And still there are more options. To see some other options and examples, take a look at this post: How to bind a column from second level list on bindsource in winforms datagridview or this one: Show Properties of a Navigation Property in DataGridView (Second Level Properties).
This should work for you:
public ISalary Salary
{
get{ return this.Salary.ToString(); };
set;
}
To use ToString(), you only append it at the end of the object you want to be returned as a string.
See the official MSDN on the ToString() function:
Object.ToString Method
interface ISalary
{
public decimal Amount { get; set; }
public string GetSalaryString();
}
the code:
List<Employee> lstEmployee = GetEmployeeList();
dataGridView1.Rows.Clear();
if (lstEmployee.Count == 0)
return;
foreach (var employee in lstEmployee)
{
DataGridViewRow dgvr = dataGridView1.Rows[dataGridView1.Rows.Add()];
dgvr.Cells[colnId.Index].Value = employee.Id;
dgvr.Cells[colnName.Index].Value = employee.Name;
dgvr.Cells[colnGender.Index].Value = employee.Gender;
dgvr.Cells[colnDepartmentId.Index].Value = employee.DepartmentId;
dgvr.Cells[colnSalary.Index].Value = employee.Salary.GetSalaryString();
}

Glass mapper populate list from Link path

I'm trying to populate a list on my current model with subitems from a different folder.
On my current model I want to define a field of type General Link in which I will select an item from Sitecore who has different subitems.
The "public virtual IEnumerable List" should be populated with the above subitems.
I have read different posts related to how you can make the following type of queries:
[SitecoreQuery("./*[##templatename='Testimonial']", IsRelative = true)]
public virtual IEnumerable Children { get; set; }
but this does not apply in my case because most probably I will have this template in different areas which I do not want to be included here.
Does anyone know if this is possible with Glass or should I just use a custom query to populate the list with an item subitems?
If you use a droplink or droptree field, rather than a General Link, you could do what you want by creating a generic Folder model.
namespace MySite.Models
{
[SitecoreType(AutoMap = true)]
public class Folder<T> : GlassBase
{
[SitecoreChildren]
public virtual IEnumerable<T> Children { get; set; }
}
}
And then use it from another model like so:
[SitecoreField("My Link Field")]
public virtual Folder<ChildModel> MyLinkField { get; set; }

What is it called when a class property is an instance of another class?

Very basic question here, look at my property Order in my customer class. Wondering what is the formal name of a property type like this is (yes, this could also be a list).
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public Order Orders { get; set; } // what am i called?
}
public class Order
{
public int ID { get; set; }
public string SomeProperty { get; set; }
}
Its the same thing. Its called a "Property". There is no different name for it. Consider your SomeProperty which is of type string. string is also a class and SomeProperty is its object. Same convention with your class would follow as well.
From C# Language Specification.
1.6.7.2 Properties
A property is declared like a field, except that the declaration ends
with a get accessor and/or a set accessor written between the
delimiters { and } instead of ending in a semicolon.
So the term "property" in C# is associated with the accessors (get/set)
from ECMA-334 8.7.4:
A property is a member that provides access to a characteristic of an object or a class.
It doesn't matter what type the property accesses. The property itself is just to provide access to it.
So, bottom line, a property is a property no matter what type it accesses.
It's just a property - there's not a formal name for it.
The concept itself is called Composition. Basically, you want to be able to use a Customer object to get information about an Order, but you don't want the logic that gets that information to live in Customer. So, you have a member who is an Order and Order encapsulates the Order behavior.
You could say that a Customer is composed of Order along with other values.
Have a link: http://www.javaworld.com/jw-11-1998/jw-11-techniques.html
Not that you asked this, but you probably will want an actual collection of Orders. You could start with
public List<Order> Orders;
It's still a property. It just gets/sets an object, which is an instance of a class.

An alternative lookup table approach needed to make C# models more generic

I currently have the following Models in my EF Code First MVC project (edited for brevity):
public class Car
{
public int Id { get; set; }
public string Descrip { get; set; }
// Navigation Property.
public virtual CarColour CarColour { get; set; }
... + numerous other navigation properties.
}
public class CarColour
{
public int Id { get; set; }
public string ColourName { get; set; }
}
The CarColour table in the DB contains many rows.
In my project, I have about 10 of these sorts of tables, which are essentially lookup tables.
Rather than have 10 lookup tables (and 10 corresponding 'hard' types in code), I was tasked with implementing a more re-usable approach, instead of having loads of lookup tables, specific to Car (in this example), along the lines of having a couple of tables, one of which may hold the item types (colour, fuel-type etc.) and one which contains the various values for each of the types. The idea being that our model will be able to be re-used by many other projects - some of which will have potentially hundreds of different attributes, and as such, we won't want to create a new Class/Type in code and generate a new lookup table for each.
I am having difficulty in understanding the c# implementation of this sort of approach and hope someone may be able to give me an example of how this can be achieved in code, more specifically, how the above models would need to change, and what additional classes would be required to accomplish this?
your base entity must implement INotifyPropertyChanged and make it generic:
public virtual CarColour CarColour {
Get { return this.carColour; }
Set {
this.Carcolour; = value
OnPropertyChanged("CarColour");
}
}
For more info see :
patterns & practices: Prism in CodePlex.
http://compositewpf.codeplex.com/wikipage?title=Model%20View%20ViewModel%20(MVVM)
Greetings
Bassam
This is not necessarily specific to EF but I've been down this road and didn't really enjoy it.
I wanted to use a single table to represent 'generic' information and while I thought it was smart, it soon showed it's limitations. One of them being the complexity you need to introduce when writing queries to extract this data if you're performing more than just 'get colours for this car'.
I'd say, if your data is simple key/value and the value type is always going to be the same then go for it, it might even be worth having this a mere 'meta-data' for an object:
public class Car
{
public int Id { get; set; }
public string Descrip { get; set; }
public MetaData CarColours { get; set; }
}
public MetaData : Dictionary<int, string>
{
public MetaData(int group){}
}
Hypothetical table:
TableMetaData(int metaGroup, int metaId, string metaValue)
If you're hoping to store different types as your value and may need to perform joining on this data - avoid it and be a bit more specific.

Categories