In the table column (of type nvarchar) I store an array of string values (List <string>). To get a data model I use Entity Framework.
Model:
namespace Project.Models.Atm
{
public class MyObject
{
[JsonIgnore]
public string _Parameters { get; set; }
[NotMapped]
[JsonProperty("parameters")]
public List<string> Parameters
{
get
{
return JsonConvert.DeserializeObject<List<string>>(string.IsNullOrEmpty(_Parameters) ? "" : _Parameters);
}
set
{
_Parameters = JsonConvert.SerializeObject(value);
}
}
}
}
If a new list of string values is assigned to the field of the myObject.parameters object, then I will do everything well.
MyObject myObject = new MyObject();
List<string> parameters = new List<string>();
parameters.Add("value");
myObject.parameters = parameters;
But if you try to add a value to the list of objects one by one, they are not added.
MyObject myObject = new MyObject();
myObject.parameters.Add("value"); <-- The value will not be added and there will be no errors.
What could be the problem?
While executing:
myObject.parameters.Add("value");
you call:
get
{
return JsonConvert.DeserializeObject<List<string>>(string.IsNullOrEmpty(_Parameters) ? "" : _Parameters);
}
and this code is creating new list for you and you are adding to it not to the string that is actually stored in the database.
To avoid temptation of adding to this list change your property to return IEnumerable<string> instead and always assign new list to the property.
Related
I have a model for person that has dictionary to hold Gender values (the values are added in a controller). I have created a viewmodel with person class and other properties. In controller I tried to add values to dictionary in person class through an instance of viewmodel. It does not throw an error but the dictionary value is always null. The code works if I do not use viewmodel and work with model directly. Important!!!! (I have to add values to dictionary via controller) Thanks for your help. Please code below.
In Model:
public class dictionary
{
[Display(Name ="Dictionary Dropdownlist")]
public Dictionary<string,string> dpdnDict { get; set; }
}
In ViewModel:
public class dictionaryviewmodel
{
public dictionary dictInViewModel {
get { return new dictionary(); }
set { }
}
}
In Controller:
public ActionResult Index(dictionaryviewmodel dictViewModel)
{
dictViewModel.dictInViewModel.dpdnDict.Add("M", "Male");
dictViewModel.dictInViewModel.dpdnDict.Add("F", "Female");
return View(dictViewModel);
}
First of all this code is indeed throwing an exception on this line
dictViewModel.dictInViewModel.dpdnDict.Add("M", "Male");
because dictViewModel.dictInViewModel returns new dictionary() and dictViewModel.dictInViewModel.dpdnDict is null because dpdnDict isn't set anywhere in code. If you want to make this code work change your classes
public class dictionaryviewmodel
{
public class dictionaryviewmodel
{
//this getter will create dictionary instance only once
//and will always return the same instance with previously added values
//also it instantiates dpdnDict object
public dictionary dictInViewModel { get; } = new dictionary()
{
dpdnDict = new Dictionary<string, string>()
};
}
}
And I don't think you pass any data into controller on request so I'd update controller as well
public ActionResult Index()
{
dictionaryviewmodel dictViewModel = new dictionaryviewmodel();
dictViewModel.dictInViewModel.dpdnDict.Add("M", "Male");
dictViewModel.dictInViewModel.dpdnDict.Add("F", "Female");
return View(dictViewModel);
}
I need to convert this DTO
public class MyDTO
{
[JsonProperty("studentInfo")]
public StudentInfo studentInfo {get; set; }
public class StudentInfo
{
[JsonProperty("others")]
public ICollection<AnotherDTO[]> Others { get; set; }
}
public class AnotherDTO
{
[JsonProperty("name")]
public string name { get; set; }
}
}
to this model
public class MyModel
{
public StudentInfo studentInfo {get; set; }
public class StudentInfo
{
public ICollection<Another[]> Others { get; set; }
}
public class Another
{
public string name { get; set; }
}
}
I am getting hung up on the ICollection. Here is the bit where I am trying to populate ICollection Others.
private static ICollection<MyModel.Another[]> getAnothers(MyDTO myDTO, MyModel myModel)
{
List<MyModel.Another> myList = new List<MyModel.Another>();
foreach(var x in myDTO.studentInfo.Others)
{
foreach(var y in x)
{
myList.Add(new MyModel.Another
{
name = y.name
});
}
}
}
MyModel.Another[] newList;
newList = myList.ToArray();
ICollection<MyDTO.AnotherDTO[]> ic = (ICollection<MyModel.Another[]>newList.Cast<MyModel.Another[]>().ToList();
This last line is giving me the following error:
Unable to cast object of type MyModel to type MyModel[].
I would appreciate any help.
Instead of manually mapping the object, I would suggest to use AutoMapper. AutoMapper is a simple little library built to solve a deceptively complex problem - getting rid of code that mapped one object to another. You can also get Nuget package for AutoMapper
Just define the mapping for the objects -
Mapper.CreateMap<MyDTO, MyModel>();
..and simply map the object like this -
var myModelObject = Mapper.Map<MyModel>(myDtoObject);
Please refer this getting started link.
You can use a select statement to convert the collection.
var myDto = new MyDto
{
studentInfo = new MyModel.StudentInfo
{
Others = new List<AnotherDTO[]>
{
new[]
{
new AnotherDTO { Name = "a" },
new AnotherDTO { Name = "b" }
},
new[]
{
new AnotherDTO { Name = "x" },
new AnotherDTO { Name = "y" }
}
}
}
var model = new MyModel
{
studentInfo = new MyModel.StudentInfo
{
Others = dto.StudentInfo.Others
.Select(otherDtoArray =>
otherDtoArray
.Select(otherDto => new MyModel.Other {Name = otherDto.Name})).ToList()
}
Thanks for your comments everyone. My main problem was trying to convert the ICollection.
I ended up changing ICollection in my model to simply List. And it is working out nicely. I am not able to Use AutoMapper as was suggested, but I do see the value of it for case like mine.
There's all kinds of wrong in your code.
foreach(var x in myDTO.studentInfo.Others)
{
foreach(var y in x)
{
myList.Add(new MyModel.Another
{
name = y.name
});
}
Why do you need the 2nd foreach loop ? Your first foreach loop is already looping through your Others (type: ICollection). Each "x" is an instance of AnotherDTO.
Secondly, the following is completely wrong:
MyModel.Another[] newList;
newList = myList.ToArray();
ICollection<MyDTO.AnotherDTO[]> ic = (ICollection<MyModel.Another[]>newList.Cast<MyModel.Another[]>().ToList();
MyList is already a list. You're then trying to cast it as an Array and then back to a list. There's no point in doing this.
Also, you might as well just not use ICollection at all. It's heavy for nothing. Just use List.
Also don't name variables with simple letters 'a', 'b', 'x', 'y', etc... You're going to get flamed by your colleagues once you're on the job market.
Here's the corrected version of your code:
public class SomeClass
{
public static List<Another> MapAnotherDtoToAnother(List<AnotherDTO> others)
{
List<Another> anotherList = new List<Another>();
foreach(var anotherDto in others)
{
Another another = new Another();
/* Populate fields of `another` whatever they are from `anotherDto` */
another.FirstName = anotherDto.FirstName;
anotherList.Add(another);
}
return anotherList;
}
}
To convert an ICollection to List just do:
/* Convert your ICollection to a List */
List<AnotherDTO> AnotherDTOList = myDto.StudentInfo.Others.Cast<AnotherDTO>().ToList()
/* Use your static function get your non-dto counterpart */
List<Another> anothers = SomeClass.MapAnotherDtoToAnother(AnotherDTOList);
Hope it helps.
Good luck!
I am using generic method to fill my dropdown for all types
below is my code.
the entity type are as follow
public class Role
{
public string Id { get; set; }
public string Name { get; set; }
}
public class DropDown
{
public string Id { get; set; }
public string Name { get; set; }
}
i am able to fetch data successfully at
var data = DataFetcher.FetchData<T>();
private static void Main( string[] args )
{
List<DropDown> cities = BLL.GetDataList<City>();
List<DropDown> states = BLL.GetDataList<State>();
List<DropDown> roles = BLL.GetDataList<Role>();
}
public static class BLL
{
public static List<DropDown> GetDataList<T>() where T : class ,new()
{
var data = DataFetcher.FetchData<T>();
return data as List<DropDown>;
}
}
I knew this cast data as List<DropDown> will fail,thats why its returning null back to calling method,
How can i cast Generic list to List of Known Type?
You have to ask yourself: how do I want to convert T to DropDown? If you can't answer this, the answer is: you can't.
I guess your DropDown class has an object Value property, that holds the dropdown value, and you wish to assign the data entity to that property.
Then you can project the list of data entities to DropDowns as such:
var data = DataFetcher.FetchData<T>();
return data.Select(d => new DropDown { Value = d }).ToList();
As for your edit: so you have at least one type, the displayed Role, that has an Id and Name property. But type T doesn't guarantee this, so you'd need to introduce an interface:
public interface INamedIdentifyableEntity
{
string Id { get; set; }
string Name { get; set; }
}
And apply this to your entities. Then introduce it as a generic constraint and do the mapping:
return data.Select(d => new DropDown
{
Id = d.Id,
Name = d.Name,
}).ToList();
But you don't want this, as here you are tying these two properties to dropdowns. Tomorrow you'll want an entity with Code instead of Id and Text instead of Name, so you'll have to add more interfaces, more overloads, and so on.
Instead you might want to use reflection, where you can specify the member names in the call:
List<DropDown> cities = BLL.GetDataList<City>(valueMember: c => c.CityCode, displayMember: c => c.FullCityname);
And use these member expressions to look up data's values and fill those into the DropDown.
However, you're then reinventing the wheel. Leave out your DropDown class entirely, and leave the dropdown generation to the front end, in this case MVC:
var cities = DataFetcher.FetchData<City>();
var selectList = new SelectList(cities.Select(c => new SelectListItem
{
Selected = (c.Id == selectedCityId),
Text = c.FullCityName,
Value = c.CityCode,
});
Or:
var selectList = new SelectList(cities, "CityCode" , "FullCityName", selectedCityId);
One solution is to use AutoMapper.
First create a map between your models like this:
AutoMapper.Mapper.CreateMap<Role, DropDown>();
Do the same thing for City and State classes if you need to.
Then you can use AutpMapper to convert your objects to DropDown like this:
public static List<DropDown> GetDataList<T>() where T : class ,new()
{
var data = DataFetcher.FetchData<T>();
return data.Select(x => AutoMapper.Mapper.Map<DropDown>(x)).ToList();
}
If I understood the question correctly, you could use Linq as follows.
return data.Cast<DropDown>().ToList();
I'm brand new to MongoDB in C#.
I have created a very simple class which I would like to automatically insert into a collection.
How do I do that, if I don't want to map everything manually?
public class DummyClass
{
[BsonId]
public int Id { set; get; }
[BsonElement("first")]
public string First { set { _name = value; } }
[BsonConstructor]
public DummyClass()
{
Id = 2;
First = "1";
}
}
I had hoped I could do something like this:
_dbClient = new MongoClient();
_database = _dbClient.GetDatabase("testDB");
_collection = _database.GetCollection<BsonDocument>("Collection");
var doc = BsonDocument.Create(dummy);
_collection.InsertOneAsync(doc);
But it's no good. I get the exception:
System.ArgumentException : .NET type DummyClass cannot be mapped to BsonType.Document.
Parameter name: value
Any suggestions?
And I really don't want to do:
{
{"Id", "2"},
{"First", "1"},
}
EDIT:
I forgot this small line:
BsonClassMap.RegisterClassMap<DummyClass>();
It does wonders.
It makes sense to use BsonDocument when fields in collections don't match properties in your model class. Otherwise you should create collection mapped to your class.
_collection = _database.GetCollection<DummyClass>("Collection");
await _collection.InsertOneAsync(doc);
And don't forget about async/await methods in MongoDB.Driver.
You can use ToBsonDocument()
_collection.InsertOneAsync(doc.ToBsonDocument())
I am working on serializing a viewmodel with MVC5 with JsonConvert.SerializeObject and the result is coming up with is an array for each record (e.g. [{PropertyName: Value,...},{PropertyName: Value,...}]. I am trying to fill a slick grid to get the property names dynamically and I have seen others have arrays that have the Property names in one array and then the data rows in another. How can I create [{Column Names},{DataRowValues}] so i can get the property names from this array. I will be deserializing this data as well. I was using this link as a reference, but I am using a List and had trouble making it work Formatting output of Newtonsoft.Json.JsonConvert.SerializeObject(dataSet). Thanks.
[HttpGet]
public JsonResult GeneratePlans()
{
//code here to create and populate view model
return Json(JsonConvert.SerializeObject(viewModel, Formatting.Indented, new JsonSerializerSettings { }), JsonRequestBehavior.AllowGet);
}
On the server, if you need dynamic property resolution, you can use reflection to enumerate the properties and values of your view model.
Since you wish to have your JSON split into an array for property names and an array for property values, we need a class to hold that result. I've left this class deliberately simple since it will just be used for holding values for JSON serialization.
class ObjectPropertyNamesAndValues
{
public List<string> Names { get; set; }
public List<object> Values { get; set; }
}
Here is a function that will populate an instance of ObjectPropertyNamesAndValues given a viewModel instance of any type.
ObjectPropertyNamesAndValues GetObjectPropertyNamesAndValues(object viewModel)
{
if (viewModel == null)
return null;
var result = new JsonObjectPropertyValues();
result.Names = new List<string>();
result.Values = new List<object>();
var propertyInfo = viewModel.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in propertyInfo)
{
if (!propertyInfo.CanRead)
continue;
// you can add other checks here, too, such as whether or not
// the property has a certain custom attribute or not
result.Names.Add(propertyInfo.Name);
result.Values.Add(property.GetValue(viewModel));
}
return result;
}
Now you can implement your function like this:
[HttpGet]
public JsonResult GeneratePlans()
{
//code here to create and populate view model
// get the object properties and values for transport as JSON
Debug.Assert(viewModel != null);
var objectPropertyNamesAndValues = GetObjectPropertyNamesAndValues(viewModel);
return Json(JsonConvert.SerializeObject(objectPropertyNamesAndValues, Formatting.Indented, new JsonSerializerSettings { }), JsonRequestBehavior.AllowGet);
}