Accessing value by key in property dictionary - c#

Im trying to access and display the value of a dictionary where the dictionary has no real name but is a property of a class.
Currently I have an enum "Roles" with three elements (fighter, rogue, and sorcerer), and:
public class Adventurer
{
public int ID { get; set; }
public string Name { get; set; }
public Roles Role { get; set; }
public List<Skill> Skills { get; set; }
public override string ToString()
{
return $"{ID}" + " - " + $"{Name}" + " - " + $"{Role}";
}
}
and:
public class Skill
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Dictionary<Roles, Skill> LinkedTo { get; set; }
}
and in another class I have:
private void CreateSkills()
{
Skill swordFighting = new Skill() { ID = 1, Name = "Sword fighting"};
Skill stealth = new Skill() { ID = 2, Name = "Stealth"};
Skill magic = new Skill() { ID = 3, Name = "Magic"};
swordFighting.LinkedTo = new Dictionary<Roles, Skill>
{
{ Roles.Fighter, swordFighting }
};
stealth.LinkedTo = new Dictionary<Roles, Skill>
{
{ Roles.Rogue, stealth }
};
magic.LinkedTo = new Dictionary<Roles, Skill>
{
{ Roles.Sorcerer, magic }
};
}
private void DisplaySkills(Adventurer adventurer)
{
adventurer.Skills = adventurer.Role.LinkedTo; // I WOULD LIKE SOMETHING LIKE THIS...
lstAdventurer.ItemsSource = adventurer.Skills;
}
Is there some way of accessing the values (skills) of the adventurer by knowing only the role (fighter/rogue/sorcerer)?
Best,
Dedoj

Would you mean something like this?
for known Roles like Roles.Fighter:
adventurer.Skills = adventurer.Skills
.Select(s => s.LinkedTo.ContainsKey(Roles.Fighter) ? s.LinkedTo[Roles.Fighter] : null)
.Where(s => s != null).ToList();

Related

C# Bad Performance OData when using extension

I have a Web API for OData services. I have a lot of table with many relations. Here is some of the table:
MSADDRESSCOUNTRY
public partial class MSADDRESSCOUNTRY
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2214:DoNotCallOverridableMethodsInConstructors")]
public MSADDRESSCOUNTRY()
{
this.MSADDRESSPROVINCEs = new HashSet<MSADDRESSPROVINCE>();
}
public int ID { get; set; }
public string CODE { get; set; }
public string COUNTRYNAME { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MSADDRESSPROVINCE> MSADDRESSPROVINCEs { get; set; }
}
MSADDRESSPROVINCE
public partial class MSADDRESSPROVINCE
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MSADDRESSPROVINCE()
{
this.MSADDRESSDISTRICTs = new HashSet<MSADDRESSDISTRICT>();
}
public int ID { get; set; }
public Nullable<int> COUNTRYID { get; set; }
public string PROVINCENAME { get; set; }
public virtual MSADDRESSCOUNTRY MSADDRESSCOUNTRY { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MSADDRESSDISTRICT> MSADDRESSDISTRICTs { get; set; }
}
MSADDRESSDISTRICT
public partial class MSADDRESSDISTRICT
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MSADDRESSDISTRICT()
{
this.MSADDRESSSUBDISTRICTs = new HashSet<MSADDRESSSUBDISTRICT>();
}
public int ID { get; set; }
public Nullable<int> PROVINCEID { get; set; }
public string DISTRICTNAME { get; set; }
public virtual MSADDRESSPROVINCE MSADDRESSPROVINCE { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MSADDRESSSUBDISTRICT> MSADDRESSSUBDISTRICTs { get; set; }
}
I create DTO object model for every table with the property is the same with Database object model.
I want the client can use $expand keyword to get child data and/or parent data.
For MSADDRESSCOUNTRY I need to write the code like this.
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<MsAddressCountryObject> Get()
{
return db.MSADDRESSCOUNTRies.Select(c => new MsAddressCountryObject
{
ID = c.ID,
CODE = c.CODE,
COUNTRYNAME = c.COUNTRYNAME,
MSADDRESSPROVINCEs = c.MSADDRESSPROVINCEs.Select(data => new MsAddressProvinceObject()
{
ID = data.ID,
COUNTRYID = data.COUNTRYID,
PROVINCENAME = data.PROVINCENAME,
MSADDRESSCOUNTRY = new MsAddressCountryObject()
{
ID = data.MSADDRESSCOUNTRY.ID,
CODE = data.MSADDRESSCOUNTRY.CODE,
COUNTRYNAME = data.MSADDRESSCOUNTRY.COUNTRYNAME,
},
MSADDRESSDISTRICTs = data.MSADDRESSDISTRICTs.Select(dist => new MsAddressDistrictObject()
{
ID = dist.ID,
PROVINCEID = dist.PROVINCEID,
DISTRICTNAME = dist.DISTRICTNAME,
})
})
});
}
For MSADDRESSPROVINCE I need to write the code like this.
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<MsAddressProvinceObject> Get()
{
return db.MSADDRESSPROVINCEs.Select(data => new MsAddressProvinceObject()
{
ID = data.ID,
COUNTRYID = data.COUNTRYID,
PROVINCENAME = data.PROVINCENAME,
MSADDRESSCOUNTRY = new MsAddressCountryObject()
{
ID = data.MSADDRESSCOUNTRY.ID,
CODE = data.MSADDRESSCOUNTRY.CODE,
COUNTRYNAME = data.MSADDRESSCOUNTRY.COUNTRYNAME,
},
MSADDRESSDISTRICTs = data.MSADDRESSDISTRICTs.Select(dist => new MsAddressDistrictObject()
{
ID = dist.ID,
PROVINCEID = dist.PROVINCEID,
DISTRICTNAME = dist.DISTRICTNAME
})
});
}
That code works fast. But if I add/change/remove column, I have to modify the controller manually, one by one for all controller. For example, if I want to add geological coordinate in MSADDRESSDISTRICT, I have to change the code in Country Controller, Province Controller and District Controller.
So I decide to create extension method like this.
public static MsAddressCountryObject ToDTO(this MSADDRESSCOUNTRY data)
{
return new MsAddressCountryObject()
{
ID = data.ID,
CODE = data.CODE,
COUNTRYNAME = data.COUNTRYNAME,
};
}
public static IQueryable<MsAddressCountryObject ToDTO(this IEnumerable<MSADDRESSCOUNTRY datas)
{
return datas.Select(country =
{
var obj = country?.ToDTO();
obj.MSADDRESSPROVINCEs = country.MSADDRESSPROVINCEs?.ToDTO();
return obj;
}).AsQueryable();
}
public static MsAddressProvinceObject ToDTO(this MSADDRESSPROVINCE data)
{
return new MsAddressProvinceObject()
{
ID = data.ID,
COUNTRYID = data.COUNTRYID,
PROVINCENAME = data.PROVINCENAME,
MSADDRESSCOUNTRY = data.MSADDRESSCOUNTRY?.ToDTO()
};
}
public static IQueryable<MsAddressProvinceObject ToDTO(this IEnumerable<MSADDRESSPROVINCE datas)
{
return datas.Select(province =
{
var obj = province?.ToDTO();
obj.MSADDRESSDISTRICTs = province.MSADDRESSDISTRICTs.ToDTO();
return obj;
}).AsQueryable();
}
public static MsAddressDistrictObject ToDTO(this MSADDRESSDISTRICT data)
{
return new MsAddressDistrictObject()
{
ID = data.ID,
PROVINCEID = data.PROVINCEID,
DISTRICTNAME = data.DISTRICTNAME,
MSADDRESSPROVINCE = data.MSADDRESSPROVINCE?.ToDTO()
};
}
public static IQueryable<MsAddressDistrictObject ToDTO(this IEnumerable<MSADDRESSDISTRICT datas)
{
return datas.Select(district =
{
var obj = district?.ToDTO();
obj.MSADDRESSSUBDISTRICTs = district.MSADDRESSSUBDISTRICTs?.ToDTO();
return obj;
}).AsQueryable();
}
And the controller just like this.
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<MsAddressCountryObject Get()
{
return db.MSADDRESSCOUNTRies.ToDTO()
}
And that makes the performance really bad. I think the extension is making a lot of memory allocation or some thing that make the result not being delivered directly to the client.
My goal is to create the code easy to maintain, and the performance not drop significantly.
I have many relation in other table. I want the $expand works without write all parent/child Select statement manually and one by one.
I have try to not calling ToDTO() from all the extension method. The result is the performance is fast. But I lost all the relation or I need to write the parent/child Select statement for all method.
Any suggestion will help.
Thanks.

One to many mapping on query dapper

I'm trying to query one to many on dapper but for some reason I only get 1 value back from my joined table even though I should be getting multiple as from my query
Can someone tell me what I did wrong?
I tried doing what was mentioned in the following post answer Mapping one to many with Dapper
My code:
public class MonsterDatabase
{
public int Id { get; set; }
public int MonsterId { get; set; }
public string Name { get; set; }
public List<MonsterLocationDatabase> Location { get; set; }
}
public class MonsterLocationDatabase
{
public int Id { get; set; }
public int FkMonsterId { get; set; }
public string Map { get; set; }
public int Frequency { get; set; }
public string MapImage { get; set; }
public DateTime? DeathTime { get; set; }
public DateTime? RespawnTime { get; set; }
}
public static MonsterDatabase GetMonster(Monster monster)
{
using (var connection = new SqlConnection(config["appsettings:RagnaDatabase"]))
{
var Monster = connection.Query<MonsterDatabase, MonsterLocationDatabase, MonsterDatabase>(
"select top 1 Monster.*, SplitMonster = '', MonsterLocation.*" +
" from Monster" +
" join MonsterLocation" +
" on Monster.Id = MonsterLocation.FkMonsterId",
(Monster, Location) =>
{
Monster.Location = new List<MonsterLocationDatabase>();
Monster.Location.Add(Location);
return Monster;
}, splitOn: "SplitMonster"
).FirstOrDefault();
return Monster;
}
}
I was able to fix the issue by following the one to many dapper documentation on
https://dapper-tutorial.net/result-multi-mapping
public static MonsterDatabase GetMonster()
{
using (var connection = new SqlConnection(config["appsettings:RagnaDatabase"]))
{
var monsterDictionary = new Dictionary<int, MonsterDatabase>();
var Monster = connection.Query<MonsterDatabase, MonsterLocationDatabase, MonsterDatabase>(
"select top 10 Monster.*, SplitMonster = '', MonsterLocation.*" +
" from Monster" +
" left join MonsterLocation" +
" on Monster.Id = MonsterLocation.FkMonsterId",
(Monster, Location) =>
{
MonsterDatabase monsterEntry;
if(!monsterDictionary.TryGetValue(Monster.Id, out monsterEntry))
{
monsterEntry = Monster;
monsterEntry.Location = new List<MonsterLocationDatabase>();
monsterDictionary.Add(monsterEntry.Id, monsterEntry);
}
monsterEntry.Location.Add(Location);
return monsterEntry;
}, splitOn: "SplitMonster"
).Distinct().FirstOrDefault();
return Monster;
}
}

Pass list from model class to DbInitliazer

I'm new to C#. I'm working on a web app project. I want to know how to initialize the list in my DbInitializer class. For example, this is the Model:
using System;
using System.Collections.Generic;
namespace Manager.Model
{
public class Vendor
{
public int VendorID { get; set; }
public string CardName { get; set; }
public string WebsiteLink { get; set; }
public DateTime PartnerSince { get; set; }
public List<Rep> Reps { get; set; }
public string SupportNo { get; set; }
public string SupportEmail { get; set; }
public string Rebate { get; set; }
public string Spiff { get; set; }
public string Quote { get; set; }
}
public class Rep
{
public string RepName { get; set; }
public string RepPosition { get; set; }
public string RepNo { get; set; }
public string RepEmail { get; set; }
}
}
How would I pass this list in the Initialize method?
public static void Initialize(ManagementContext context)
{
context.Database.EnsureCreated();
// Look for any students.
if (context.Vendors.Any())
{
return; // DB has been seeded
}
var vendors = new Vendor[]
{
new Vendor{CardName="Vendor1", WebsiteLink="www.vendor1.com", PartnerSince=DateTime.Parse("10-10-2012"), SupportNo="521-586-8956", SupportEmail="nikki#vendor1.com"},
};
foreach (Vendor v in vendors)
{
context.Vendors.Add(v);
}
context.SaveChanges();
If you'd like to do everything inline:
Vendor[] vendors = new Vendor[]
{
new Vendor() // first vendor
{
CardName="Vendor1",
WebsiteLink="www.vendor1.com",
PartnerSince=DateTime.Parse("10-10-2012"),
SupportNo="521-586-8956",
SupportEmail="nikki#vendor1.com",
Reps = new List<Rep>()
{
new Rep() // first rep
{
RepName = "name",
RepPosition = "pos",
RepNo = "no",
RepEmail = "email"
}
// , new Rep(){...} // second rep, etc...
}
}
// , new Vendor(){....} // second vendor, etc...
};
Or simply prepare the Reps first:
List<Rep> Reps1 = new List<Rep>(); // Reps 1 for Vendor 1
Reps1.Add(new Rep()
{
RepName = "name",
RepPosition = "pos",
RepNo = "no",
RepEmail = "email"
});
// you may add more rep
then assign it in vendor
Vendor[] vendors = new Vendor[]
{
new Vendor() // first vendor
{
CardName="Vendor1",
WebsiteLink="www.vendor1.com",
PartnerSince=DateTime.Parse("10-10-2012"),
SupportNo="521-586-8956",
SupportEmail="nikki#vendor1.com",
Reps = Reps1
}
// , new Vendor(){....} // second vendor, etc...
};
For question if you change into string[] RepNames,
string[] RepNames1 = new string[]
{
"name1",
"name2" // , etc....
}
then assign it in vendor
Vendor[] vendors = new Vendor[]
{
new Vendor() // first vendor
{
CardName="Vendor1",
WebsiteLink="www.vendor1.com",
PartnerSince=DateTime.Parse("10-10-2012"),
SupportNo="521-586-8956",
SupportEmail="nikki#vendor1.com",
RepNames = RepNames1
}
// , new Vendor(){....} // second vendor, etc...
};

Get a particular instance of a class

I have created a model for UnitOfMeasure (UOM) and a model for ingredient where I would like to use UOM to enter a default UOM for the ingredient.
public class IngredientModel
{
public int Id { get; set; }
public string Name { get; set; }
public UnitOfMeasureModel DefaultUOM { get; set; }
}
public class UnitOfMeasureModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
I would like to use the Name property in the IngredientModel.
In configure.cs I have put this code to create some default data for the database:
protected override void Seed(RecipeApplication.Models.RecipeApplicationDb context)
{
if (!context.UnitOfMeasures.Any())
{
context.UnitOfMeasures.AddOrUpdate(
u => u.Id,
new UnitOfMeasureModel { Name = "Gram", Abbreviation = "g" },
new UnitOfMeasureModel { Name = "Kilogram", Abbreviation = "kg"},
new UnitOfMeasureModel { Name = "Milligram", Abbreviation = "mg" }
);
}
if (!context.Ingredients.Any())
{
context.Ingredients.AddOrUpdate(
i => i.Id,
new IngredientModel { Name = "Italiaanse Ham", DefaultUOM =
);
}
}
I did not enter anything yet at default UOM because that is where I got stuck.
Could someone help me with this issue?
I'm assuming you just want to be able to access one of the UnitOfMeasureModel classes in both the UnitOfMeasures.AddOrUpdate and the UnitOfMeasures.AddOrUpdate methods. To do this create the instance before the calls and use that same instance in each AddOrUpdate method like so.....
protected override void Seed(RecipeApplication.Models.RecipeApplicationDb context)
{
var defaultUOM = new UnitOfMeasureModel { Name = "Gram", Abbreviation = "g" };
if (!context.UnitOfMeasures.Any())
{
context.UnitOfMeasures.AddOrUpdate(
u => u.Id,
defaultUOM,
new UnitOfMeasureModel { Name = "Kilogram", Abbreviation = "kg"},
new UnitOfMeasureModel { Name = "Milligram", Abbreviation = "mg" }
);
}
if (!context.Ingredients.Any())
{
context.Ingredients.AddOrUpdate(
i => i.Id,
new IngredientModel { Name = "Italiaanse Ham", DefaultUOM = defaultUOM
);
}
}
obviously you can change if gram is not the correct default

RavenDB query with Linq and enum

Given this document class:
public class Tea
{
public String Id { get; set; }
public String Name { get; set; }
public TeaType Type { get; set; }
public Double WaterTemp { get; set; }
public Int32 SleepTime { get; set; }
}
public enum TeaType
{
Black,
Green,
Yellow,
Oolong
}
I store a new Tea with the following code:
using (var ds = new DocumentStore { Url = "http://localhost:8080/" }.Initialize())
using (var session = ds.OpenSession("RavenDBFirstSteps"))
{
Tea tea = new Tea() { Name = "Earl Grey", Type = TeaType.Black, WaterTemp = 99d, SleepTime = 3 };
session.Store(tea);
session.SaveChanges();
Console.WriteLine(tea.Id);
}
The tea will be successfully saved, but when I try to query all black teas with linq, I am getting no results:
using (var ds = new DocumentStore { Url = "http://localhost:8080/" }.Initialize())
using (var session = ds.OpenSession("RavenDBFirstSteps"))
{
var dbTeas = from teas in session.Query<Tea>()
where teas.Type == TeaType.Black
select teas;
foreach (var dbTea in dbTeas)
{
Console.WriteLine(dbTea.Id + ": " + dbTea.Name);
}
}
I also tried to save the Enum as Integer with the following command:
ds.Conventions.SaveEnumsAsIntegers = true;
But, the result is the same. All works when I use the Name or the WaterTemp. Does RavenDB supports Enums in this way or I am totally wrong?
It seemed that I got the answer. It is always not recommended to use properties with a name like Type, which can be a reserved keyword.
I renamed Type and everything works, so the answer is:
public class Tea
{
public String Id { get; set; }
public String Name { get; set; }
public TeaType TeaType { get; set; }
public Double WaterTemp { get; set; }
public Int32 SleepTime { get; set; }
}

Categories

Resources