ASP.NET MVC 2: Manually create a list and attach to model - asp.net-mvc-2

I have a model:
[Required]
public List<SelectList> Meals { get; set;
}
And I want to create a list in my Controller so I can attach it to "Meals" in my Model.
For some reason I'm having issues doing this:
_model.MaxCoupons = new List<SelectListItem>();
SelectListItem _mList = new SelectListItem([]{
new SelectListItem { Text = "---", Value = "" },
new SelectListItem { Text = "50", Value = "50" },
new SelectListItem { Text = "60", Value = "60" },
new SelectListItem { Text = "70", Value = "70" },
new SelectListItem { Text = "80", Value = "80" },
new SelectListItem { Text = "90", Value = "90" },
new SelectListItem { Text = "100", Value = "100" },
new SelectListItem { Text = "110", Value = "110" },
new SelectListItem { Text = "120", Value = "120" },
new SelectListItem { Text = "130", Value = "130" },
new SelectListItem { Text = "140", Value = "140" },
new SelectListItem { Text = "150", Value = "130" } },
"Text", "Value" );
_model.MaxCoupons.Add(_mList);
I'm a bit confused right now...

public SelectList Meals { get; set; }
public SelectList MySelectList()
{
List<SelectListItem> _returnList = new List<SelectListItem>();
SelectListItem _mList = new SelectListItem();
_mList = new SelectListItem(){ Text = "---", Value = "" };
_returnList.Add(_mList);
//keep repeating
}
then inside a method:
Meals = new MySelectList();

Related

Included property returns object that it's included to

I'm working on my side project with is a WebAPI in ASP.NET Core 2.1. I'm using Entity Framework Core 2.1.
I have a User:
public class User : Account
{
public UInt64 UserEmail { get; protected set; }
public UserImage UserImage { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
public User() { }
public User(string nick, UInt64 login, byte[] salt, byte[] passwordHash,
string restoreKey, UInt64 userEmail) : base(nick, login, salt, passwordHash, restoreKey)
{
UserEmail = userEmail;
Role = "user";
}
public void Update(UInt64 login, UInt64 userEmail)
{
Login = login;
UserEmail = userEmail;
UpdatedAt = DateTime.UtcNow;
}
public void UpdatePassword(byte[] newPassword)
{
PasswordHash = newPassword;
UpdatedAt = DateTime.UtcNow;
}
}
and UserImage:
public class UserImage : Image
{
public int? UserRef { get; set; }
public virtual User User { get; set; }
public UserImage() : base() { }
public UserImage(string content) : base(content) { }
}
In my DbContext I have something like this:
modelBuilder.Entity<User>()
.HasOne(x => x.UserImage)
.WithOne(y => y.User)
.HasForeignKey<UserImage>(y => y.UserRef)
.IsRequired(false);
I have a method in my service that returns a user with his image:
public async Task<User> GetAsync(int id)
{
var user = await _context.Users.GetById(id)
.Include(x => x.UserImage)
.SingleOrDefaultAsync();
if (user == null)
throw new CorruptedOperationException("Invalid id");
return user;
}
The problem is that when I use a Postman to get a user I get that kind of response:
{
"userEmail": 2606810040825320252,
"userImage": {
"userRef": 16,
"user": {
"userEmail": 2606810040825320252,
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!#g17#kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"
},
"imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
"id": 10,
"createdAt": "2018-10-16T05:45:42.4644513",
"updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!#g17#kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"
}
Like you can see I get a user with his image and in this image i get (again) this user.
I would like to get response like this:
{
"userEmail": 2606810040825320252,
"userImage": {
"userRef": 16,
"user": null,
"imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
"id": 10,
"createdAt": "2018-10-16T05:45:42.4644513",
"updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!#g17#kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"
}
Or something similar. I tried to work my way with Include() and (or without) virtual but I ended-up with this.
UPDATE
Definition for GetById():
public static IQueryable<User> GetById(this IQueryable<User> value,int id)
=> value.Where(x => x.Id == id);
You can find full project on GitHub. I'm working on branch MB#20.
For looping reference, you could not control it in EF Core.
For general handling, we configure it in Startup.cs like
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json
.ReferenceLoopHandling.Ignore;
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
});
And usecase:
var user = await _userService.GetAsync(id);
return Ok(user);
For your issue, you modified user before return by return Ok(user.ShapeData(fields)); which made JsonSerialize fail to know its the loop reference.
For a workaround, before converting to ExpandoObject, handle the loop reference like
public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
var result =JsonConvert.SerializeObject(source, new JsonSerializerSettings{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
} );
source = JsonConvert.DeserializeObject<TSource>(result);
var dataShapedObject = new ExpandoObject();
//your rest code
return dataShapedObject;
}
Update
For null in UserImage, it is caused by you specify the properties as public string ImageContent { get; protected set; }.
Try to custom DefaultContractResolver to deserialize the protected properties.
IncludePrivateStateContractResolver.cs
public class IncludePrivateStateContractResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
const BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
var properties = objectType.GetProperties(BindingFlags);//.Where(p => p.HasSetter() && p.HasGetter());
var fields = objectType.GetFields(BindingFlags);
var allMembers = properties.Cast<MemberInfo>().Union(fields);
return allMembers.ToList();
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var prop = base.CreateProperty(member, memberSerialization);
if (!prop.Writable)
{
var property = member as PropertyInfo;
if (property != null)
{
prop.Writable = property.HasSetter();
}
else
{
var field = member as FieldInfo;
if (field != null)
{
prop.Writable = true;
}
}
}
if (!prop.Readable)
{
var field = member as FieldInfo;
if (field != null)
{
prop.Readable = true;
}
}
return prop;
}
}
public static class TypeExtensions
{
public static bool HasSetter(this PropertyInfo property)
{
//In this way we can check for private setters in base classes
return property.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Any(m => m.Name == "set_" + property.Name);
}
public static bool HasGetter(this PropertyInfo property)
{
//In this way we can check for private getters in base classes
return property.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Any(m => m.Name == "get_" + property.Name);
}
}
usecase:
public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
var soureType = source.GetType();
if (source == null)
{
throw new ArgumentNullException("source");
}
var serializeSettings = new JsonSerializerSettings{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var deserializeSettings = new JsonSerializerSettings{
ContractResolver = new IncludePrivateStateContractResolver()
};
var result =JsonConvert.SerializeObject(source, serializeSettings );
var castType = JsonConvert.DeserializeObject<TSource>(result, deserializeSettings);
var dataShapedObject = new ExpandoObject();
I managed to fix my problem. I changed all private setters in models properties to public an used Tao Zhou original answer.
My ShapeData method:
public static ExpandoObject ShapeData<TSource>(this TSource source, string fields)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
var result = JsonConvert.SerializeObject(source, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
source = JsonConvert.DeserializeObject<TSource>(result);
var dataShapedObject = new ExpandoObject();
// rest of my code
}
User:
public class User : Account
{
public UInt64 UserEmail { get; set; }
public UserImage UserImage { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
// rest of the code
}
UserImage:
public class UserImage : Image
{
public int? UserRef { get; set; }
public virtual User User { get; set; }
public UserImage() : base() { }
public UserImage(string content) : base(content) { }
}
Example of the returned data:
{
"userEmail": 2606810040825320252,
"userImage": {
"userRef": 16,
"user": null,
"imageContent": "/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjZ/jPZ6rHocDfFz4iNI19b3BU+FdFjYiEho2/5A6l8Mi53Eg4bIbkj3Sx/bi0/T/2dde0CP8AaL1xdvhK+i+w3EeiQCeR4r7bA2NMj3rtnLhScEyLtJZRt+a/2fH8S/Ha5t77wn4x+Hfiqy0q8neCHRrW8vL2dTpuq3bhbeOOWbcqQNshdDNI8kaRqzAkYXiT9tDxF8DLbxlp+peE9b8davp8b6fdaB4ZsL9LqKFZJI57m9lubJhp6o6JGYZojch2w8UIwzEpSneEd9OtjOPJDV7el/yP2V+Hv7VvhvxLrhcftfaTHYl5CkWpXfhhHwJJFCsBBG4OAp6Y57cVjfAL9rHwj4Y/Zx+HMM37YXwb0KSPw7pkLWep3OjF4X+zQp5J/wBJjbcGIXB5yQOtfLn7FH/BbZpPA0eqN8N/EXgLVoI7u5utD8f6nqVrDeRxh5B/Z15baNLFdyNiSMwlIpt6/LG6q7pa0T/gtFefD79kf4e3uo6h8CdBsdA8N2S2clz8ablL7Xo47GMFhpy6FJM8i5IKhSySoACzqm6fehG1rtFq0pXvZH4L/sdftNWH7OOo61f65pt94g0W7sWsY9OsPEUmky3N23EMjT2zrcxLFG9w6tGrK0gjjcFJHFdR8ef2620zXZtY+EPi/wCLWh3HisTy+JLbxFqqXVxb3MgdHe0voPLdoZI3QFJIw6vACXkDkD550T4a61qHmC3jhZmwCd3T9K0JPgT4vZvlsvM3DGVfj9a6oymlaK179TCXI37z07dD6k+B3/BT/VPF+ixt8dvGnxw+JMvhXVDqnhfQtP8AEUVnZ3FxPb/Zp5r69niuLhsQBo4lEbGP7ROysm+RJfIf21v2pNU/a++KknjTVJLiBZ4I9IhtL3xFNq1zp0NuCY4fOu5ZLuaNVkAEk5JJ3ruYoSeb8IfslfEDxEFa2t7W3C95p9nqewNaXxW/Z48caV4b0e21OOzm/s8zKskV2824OwY/KVG0jpkZJGAeAMaSjVlG8l87av5mcalGMrRa9L6L0Wx//9k=",
"id": 10,
"createdAt": "2018-10-16T05:45:42.4644513",
"updatedAt": "2018-10-16T05:45:42.4645292"
},
"recipes": null,
"nick": "MadBear123",
"login": 10458175107962595193,
"salt": "Fv/S1pnpu1u0RA6RxE1wfwCmqhbkb0Fu0W2sOuFgv//PHyizyPtmuaX8OtYkCgSJPlKMGmE2qFgg2rgs70Ee9bbMU26iVhtIApqV/Zxac54P9EXBvgkAXede3YHzSPzHkvGz3WchUUDIQqHF+EmdvPT9KuYR1Djgywxh0bDbSJk=",
"passwordHash": "Yk5S3jutaKJpwSQoRH0nk2At3nYL/Wzi+8QGRFOZuByi54o+YJHuhPYRMMSG3Vmimv1UMRWe+VA8ym2xQxoEJA==",
"role": "user",
"restoreKey": "Vub!#g17#kcP",
"id": 16,
"createdAt": "2018-10-14T11:11:43.9902857",
"updatedAt": "2018-10-14T11:11:43.990384"
}

How to partition a reactive observable by a key and merge the partitions into groups combine last element of each partition of the group

I have an hot observable of a sequence of items that are have a key that identifies a specific sub-stream. I'm interested to map those M streams into N with N < M (group them into N buckets). For each bucket, each time an element arrives, I want to apply a function to the latest element of each underlining sequence of that group. I've prior knowledge of both N and M groups.
In the following sample, we have a sequence of quote for four fruits. I want to map those streams into two, by the type of fruit (Apple or Pear). For each group I want to collect the last known quote of each fruit.
class Input {
public string ProductID {get;set;}
public string ProductType {get;set;}
public int Price {get;set;}
}
class Output {
public string ProductType {get;set;}
public Input[] Underlining {get;set;}
}
var obs = new List<Input> {
new Input { ProductID = "Stark", ProductType = "Apple", Price = 21 },
new Input { ProductID = "Jonagold", ProductType = "Apple", Price = 12 },
new Input { ProductID = "Williams", ProductType = "Pear", Price = 33 },
new Input { ProductID = "Beth", ProductType = "Pear", Price = 22 },
new Input { ProductID = "Stark", ProductType = "Apple", Price = 43 },
new Input { ProductID = "Williams", ProductType = "Pear", Price = 55 },
new Input { ProductID = "Beth", ProductType = "Pear", Price = 66 },
new Input { ProductID = "Jonagold", ProductType = "Apple", Price = 77 },
new Input { ProductID = "Jonagold", ProductType = "Apple", Price = 25 },
new Input { ProductID = "Williams", ProductType = "Pear", Price = 77 },
new Input { ProductID = "Beth", ProductType = "Pear", Price = 13 },
new Input { ProductID = "Stark", ProductType = "Apple", Price = 21 },
}.ToObservable();
IObservable<Output> result = obs.GroupBy ... Select ... Concat ... ; // I'm a bit loss here
result.Dump();
Expected result:
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 21 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 21 }, { ProductID = "Jonagold", Price = 12 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 23 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 23 }, { ProductID = "Beth", Price = 22 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = **43** }, { ProductID = "Jonagold", Price = 12 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = **55** }, { ProductID = "Beth", Price = 22 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 55 }, { ProductID = "Beth", Price = **66** }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 43 }, { ProductID = "Jonagold", Price = **77** }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 43 }, { ProductID = "Jonagold", Price = **25** }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = **77** }, { ProductID = "Beth", Price = 66 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 77 }, { ProductID = "Beth", Price = **13** }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = **21** }, { ProductID = "Jonagold", Price = 25 }] }
I think this is what you want:
var outputs =
obs
.GroupBy(x => x.ProductType)
.Select(xs =>
xs
.Scan(
new Dictionary<string, Input>(),
(d, x) => { d[x.ProductID] = x; return d; })
.Select(x => new Output()
{
ProductType = xs.Key,
Underlining = x.Values.ToArray(),
}))
.Merge();
I used outputs.Select(x => $"{{ ProductType = \"{x.ProductType}\", Underlining = [{String.Join(", ", x.Underlining.Select(y => $"{{ ProductID = \"{y.ProductID}\", Price = {y.Price} }}"))}] }}") to get the following output to test it:
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 21 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 21 }, { ProductID = "Jonagold", Price = 12 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 33 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 33 }, { ProductID = "Beth", Price = 22 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 43 }, { ProductID = "Jonagold", Price = 12 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 55 }, { ProductID = "Beth", Price = 22 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 55 }, { ProductID = "Beth", Price = 66 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 43 }, { ProductID = "Jonagold", Price = 77 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 43 }, { ProductID = "Jonagold", Price = 25 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 77 }, { ProductID = "Beth", Price = 66 }] }
{ ProductType = "Pear", Underlining = [{ ProductID = "Williams", Price = 77 }, { ProductID = "Beth", Price = 13 }] }
{ ProductType = "Apple", Underlining = [{ ProductID = "Stark", Price = 21 }, { ProductID = "Jonagold", Price = 25 }] }

Seeding Related Data with EF 6

I'm looking for some simple advice, I just cannot seem to get the answer (or I don't know how to ask the right question).
Here goes, I have 2 classes used to build a db using EF with Code first approach:
public class Dealer
{
public int Id { get; set; }
public string DealerName { get; set; }
}
and
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public Dealer Dealer { get; set; }
}
So, EF creates a DB for me, and in the Products table also creates a "Dealer-ID (FK, int, null)" field so that Products can be related to Dealers.
So, in order to have a nice test application (which this is), I want to Seed the DB with some info.
I create some Dealers:
context.Dealers.AddOrUpdate(
p => p.DealerName,
new Models.Dealer { DealerName = "Los Angeles" },
new Models.Dealer { DealerName = "New York" },
new Models.Dealer { DealerName = "London" },
new Models.Dealer { DealerName = "Quebec" },
new Models.Dealer { DealerName = "Gothenburg" }
);
and now I want to create some products, and relate them to Dealers at the same time. Ordinarily, I would simply put an index value into the Dealer_ID Foreign Key field in the products table, but, since this wasn't in my models class in the first place, it's not available.
I do however have a List available.
Like this:
context.Products.AddOrUpdate(
p => p.ProductName,
new Models.Product { ProductName = "Electronics",
Dealer = ???????
},
new Models.Product
{
ProductName = "Sushi",
Dealer = new Models.Dealer { DealerName = "Johannesburg" }
}
);
I successfully add a Product "Sushi", and relate it to a new dealer called "Johannesburg", but, how do I add "Electronics" to the existing dealer "London" for example. What goes in the ?????? so that I can reference an existing dealer??
I can't create new dealers for each product, since that defeats the purpose of relating the tables in the first place.
Save the dealers in a List<Dealer> (or an array) and set the Dealer property in a Product using the specific index in the list:
var dealers =new List<Models.Dealer>(){
new Models.Dealer { DealerName = "Los Angeles" },
new Models.Dealer { DealerName = "New York" },
new Models.Dealer { DealerName = "London" },
new Models.Dealer { DealerName = "Quebec" },
new Models.Dealer { DealerName = "Gothenburg" },
new Models.Dealer { DealerName = "Johannesburg" }
};
context.Dealers.AddOrUpdate(p => p.DealerName,dealers.ToArray());
context.Products.AddOrUpdate(
p => p.ProductName,
new Models.Product { ProductName = "Electronics", Dealer = dealers[2]},
new Models.Product { ProductName = "Sushi",Dealer = dealers[5]});
context.SaveChanges();
I believe what octaviocci is getting at is that you need to provide a value for the Dealer property. Entity Framework will take care of populating the Dealer_Id. That being said, I would recommend storing any of the dealers which you wish to reference in individual variables so that your code is more resilient to change and clear to read.
var laDealer = new Models.Dealer { DealerName = "Los Angeles" };
var nyDealer = new Models.Dealer { DealerName = "New York" };
var londonDealer = new Models.Dealer { DealerName = "London" };
var quebecDealer = new Models.Dealer { DealerName = "Quebec" };
var gothenburgDealer = new Models.Dealer { DealerName = "Gothenburg" };
var johannesburgDealer = new Models.Dealer { DealerName = "Johannesburg" };
var dealers =new List<Models.Dealer>(){
laDealer,
nyDealer,
londonDealer,
quebecDealer,
gothenburgDealer,
johannesburgDealer
};
context.Dealers.AddOrUpdate(p => p.DealerName,dealers.ToArray());
I would also recommend adding an additional save between the dealer creation and the products creation.
context.SaveChanges();
context.Products.AddOrUpdate(
p => p.ProductName,
new Models.Product { ProductName = "Electronics", Dealer = londonDealer},
new Models.Product { ProductName = "Sushi",Dealer = johannesburgDealer}
);
context.SaveChanges();
I recommend this because my experience has shown that in some cases the save for the dealers may not execute before the product save. This can cause a foreign key conflict. (This might only apply when the foreign key column is non-nullable, but I'm not certain.)
I was looking at these type of solutions, but I kept on thinking "it shouldn't be this complex".
I solved it eventually, and here's what I did:
You basically Instantiate a particular Dealer first, then add all the products to it...
Models.Dealer dealer1 = context.Dealers.Where(e => e.DealerName == "Los Angeles").First();
context.Products.AddOrUpdate(
p => p.ProductName,
new Models.Product
{
ProductName = "Electronics",
Dealer = dealer1
},
new Models.Product
{
ProductName = "Gourmet Food",
Dealer = dealer1
},
new Models.Product
{
ProductName = "Sushi",
Dealer = dealer1
},
new Models.Product
{
ProductName = "Beach Wear",
Dealer = dealer1
}, new Models.Product
{
ProductName = "Fast Cars",
Dealer = dealer1
});
It is important to note though, that if you're doing this, by the time the Products are to be added, there will be no Dealers committed to the DB yet, so you need to actually do this:
protected override void Seed(RelatedDataExample.Models.myContext context)
{
context.Dealers.AddOrUpdate(
p => p.DealerName,
new Models.Dealer { DealerName = "Los Angeles" },
new Models.Dealer { DealerName = "New York" },
new Models.Dealer { DealerName = "London" },
new Models.Dealer { DealerName = "Quebec" },
new Models.Dealer { DealerName = "Gothenburg" }
);
context.SaveChanges();
Models.Dealer dealer1 = context.Dealers.Where(e => e.DealerName == "Los Angeles").First();
context.Products.AddOrUpdate(
p => p.ProductName,
new Models.Product
{
ProductName = "Electronics",
Dealer = dealer1
},
new Models.Product
{
ProductName = "Gourmet Food",
Dealer = dealer1
},
new Models.Product
{
ProductName = "Sushi",
Dealer = dealer1
},
new Models.Product
{
ProductName = "Beach Wear",
Dealer = dealer1
}, new Models.Product
{
ProductName = "Fast Cars",
Dealer = dealer1
});
Models.Dealer dealer2 = context.Dealers.Where(e => e.DealerName == "Quebec").First();
context.Products.AddOrUpdate(
p => p.ProductName,
new Models.Product
{
ProductName = "Maple Syrup",
Dealer = dealer2
},
new Models.Product
{
ProductName = "Warm Jackets",
Dealer = dealer2
},
new Models.Product
{
ProductName = "Fermented Fish Head",
Dealer = dealer2
});
}
To my simple mind, this was the simplest solution.
Anyone have a better way?
Cheers
JohannS

UI5 Tree Binding to JSON

I have the following JSON file.
"idocs": [
{
"Docnum": "00063463",
"Mestyp": "MATMAS",
"Status": "53",
"Sndprn": "EXTSYS1",
"Direct": "Inbound",
"Message": "Material 00002342 Created",
"messages": [{
"message": "Material 00002342 Created"
}],
"segments": [{
"segment": "E1MARAM",
"fields": [{
"fieldName": "MATNR"
}]
}]
}
I want to bind this to a tree node. I have the following code to "attempt" to do this and it is not doing anything. Not even an error.
var oTree = new sap.ui.commons.Tree("tree")
.placeAt("idViewRoot--idViewDetail--toolBar-content");
oTree.bindAggregation("nodes", tgtPath, function(
sId, oContext) {
alert("stuff");
var treePath = oContext.getPath();
var bindTextName = '';
if (treePath.indexOf("fields") !== -1) {
bindTextName = "fieldName";
} else {
bindTextName = "segment";
}
return new sap.ui.commons.TreeNode()
.bindProperty("text", bindTextName);
});
I would appreciate if someone could take a look and point me in the right direction.
Should I see an alert "stuff" appearing, because I do not even see that. Could it be an issue with the binding.
The value of tgtPath is /idocs/0/segments.
Martin
// data has to be tree structured
var oData = {
root:{
name: "root",
0: {
name: "item1",
0: {
name: "subitem1",
0: {
name: "subsubitem1"
},
1: {
name: "subsubitem2"
}
},
1: {
name: "subitem2",
0: {
name: "subsubitem3"
}
}
},
1:{
name: "item2",
0: {
name: "subitem3"
}
}
}
};
var oModel = new sap.ui.model.json.JSONModel();
// set the data to the model
oModel.setData(oData);
var oTree = new sap.ui.commons.Tree("tree");
oTree.setWidth("100%");
// set the model to the tree
oTree.setModel(oModel);
var oTreeNodeTemplate = new sap.ui.commons.TreeNode("node");
oTreeNodeTemplate.bindProperty("text", "name");
oTreeNodeTemplate.setExpanded(true);
oTree.bindAggregation("nodes", "/root", oTreeNodeTemplate);
oTree.placeAt("body");
Here is sample https://jsbin.com/rexahoquso/edit?html,js,output

Update List items through Linq, Entity Framework

My list as below:
List<SelectListItem> items = new List<SelectListItem>();
items.Add(new SelectListItem() { Text = "Item 1", Value = "1", Selected = false });
items.Add(new SelectListItem() { Text = "Item 2", Value = "2", Selected = false });
items.Add(new SelectListItem() { Text = "Item 3", Value = "3", Selected = false });
items.Add(new SelectListItem() { Text = "Item 4", Value = "4", Selected = false });
items.Add(new SelectListItem() { Text = "Item 3", Value = "5", Selected = false });
items.Add(new SelectListItem() { Text = "Item 6", Value = "6", Selected = false });
items.Add(new SelectListItem() { Text = "Item 7", Value = "7", Selected = false });
Based on it a listbox is created.
User can select multiple items (though a listbox) and selected items stored as string (3,7 mean Item 3 and Item 7 selected). How I can update the list (before binding) to set selected true for Value 3 and 7?
string selectedItems=3,7
I can do with a for loop and search for item 3 and 7 and update Selected=True
But is there any shortcut or faster way? As I have many instances of such lists in my data entry
Cheers
I did as below:
if (selectedItems != null)
{
var Selected= items
.Where(x => selectedItems.Split(',').Any(s => x.Text.ToString().Equals(s)))
.ToList();
foreach(var item in Selected)
{
item.Selected = true;
}
}
But hopefully some better is there to avoid loop!
Cheers