我有三个非常简单的表连接在一起。其中两个表有三列,主要是整数。第三列有大约15列,主要是varchar。
表格如下:Spellbooks
,Spells
,SpellbookSpells
。对于Spellbooks
中的每条记录,SpellbookSpells
中存在零到多条记录,其中包含Spellbook_Id
和Spell_Id
的列。
所以当我得到Spellbook book = db.Spellbooks.Find(id);
时,
我得到一个具有SpellbookSpells
属性的对象,我可以用它来有效地获得List<Spell>
。这样,当我通过JSON返回数据时,它看起来有点像:
{
"SpellbookSpells": [
{
"Spell": {
"SpellbookSpells": [],
"Id": 1,
"Name": "Abi-Dalzim's Horrid Wilting",
"Description": "<p>You draw the moisture from every creature in a 30-foot cube centered on a point you choose within range. Each creature in that area must make a Constitution saving throw. Constructs and undead aren't affected, and plants and water elementals make this saving throw with disadvantage. A creature takes 10d8 necrotic damage on a failed save, or half as much damage on a successful one.You hurl a bubble of acid. Choose one creature within range, or choose two creatures within range that are within 5 feet of each other. A target must succeed on a Dexterity saving throw or take 1d6 acid damage.</p><p>This spells damage increases by 1d6 when you reach 5th Level (2d6), 11th level (3d6) and 17th level (4d6).</p>",
"Page": "ee pc 15",
"Range": "150 feet",
"Components": "V, S, M",
"Ritual": false,
"Duration": "Instantaneous",
"Concentration": false,
"CastingTime": "1 action",
"Level": 8,
"School": "Necromancy",
"Classes": "Sorcerer, Wizard",
"Archetype": null,
"Domains": null,
"Oaths": null,
"Circles": null
},
"id": 1,
"spellbook_id": 5,
"spell_id": 1
},
{
"Spell": {
"SpellbookSpells": [],
"Id": 2,
"Name": "Absorb Elements",
"Description": "<p>The spell captures some of the incoming energy, lessening its effect on you and storing it for your next melee attack. You have resistance to the triggering damage type until the start of your next turn. Also, the first time you hit with a melee attack on your next turn, the target takes an extra 1d6 damage of the triggering type, and the spell ends.</p>",
"Page": "ee pc 15",
"Range": "Self",
"Components": "S",
"Ritual": false,
"Duration": "1 round",
"Concentration": false,
"CastingTime": "1 action",
"Level": 1,
"School": "Abjuration",
"Classes": "Druid, Ranger, Wizard",
"Archetype": null,
"Domains": null,
"Oaths": null,
"Circles": null
},
"id": 3,
"spellbook_id": 5,
"spell_id": 2
},
{
"Spell": {
"SpellbookSpells": [],
"Id": 4,
"Name": "Aganazzar's Scorcher",
"Description": "<p>A line of roaring flame 30 feet long and 5 feet wide emanates from you in a direction you choose. Each creature in the line must make a Dexterity saving throw. A creature takes 3d8 fire damage on a failed save, or half as much damage on a successful one.</p>",
"Page": "ee pc 15",
"Range": "30 feet",
"Components": "V, S, M",
"Ritual": false,
"Duration": "Instantaneous",
"Concentration": false,
"CastingTime": "1 action",
"Level": 2,
"School": "Evocation",
"Classes": "Sorcerer, Wizard",
"Archetype": null,
"Domains": null,
"Oaths": null,
"Circles": null
},
"id": 4,
"spellbook_id": 5,
"spell_id": 4
},
{
"Spell": {
"SpellbookSpells": [],
"Id": 6,
"Name": "Alarm",
"Description": "<p>You set an alarm against unwanted intrusion. Choose a door, a window, or an area within range that is no larger than a 20-foot cube. Until the spell ends, an alarm alerts you whenever a Tiny or larger creature touches or enters the warded area. When you cast the spell, you can designate creatures that won’t set off the alarm. You also choose whether the alarm is mental or audible.</p><p>A mental alarm alerts you with a ping in your mind if you are within 1 mile of the warded area. This ping awakens you if you are sleeping.</p><p>An audible alarm produces the sound of a hand bell for 10 seconds within 60 feet.</p>",
"Page": "phb 211",
"Range": "30 feet",
"Components": "V, S, M",
"Ritual": true,
"Duration": "8 hours",
"Concentration": false,
"CastingTime": "1 minute",
"Level": 1,
"School": "Abjuration",
"Classes": "Ranger, Ritual Caster, Wizard",
"Archetype": null,
"Domains": null,
"Oaths": null,
"Circles": null
},
"id": 5,
"spellbook_id": 5,
"spell_id": 6
}
],
"Id": 5,
"Name": "Krud",
"UserId": "6922cf7c-6a86-4b7b-89d9-32ebbae43b8f"
}
但是,我想要的Spell
的唯一属性是Id
,Name
,Level
和Classes
如何点Spellbook book = db.Spellbooks.Find(id);
并仅选择Spells
的特定列?
答案 0 :(得分:2)
生成所需数据的基本查询是
var spellData = from sbs in db.SpellBookSpells
where sbs.SpellBook_Id == id
select new
{
sbs.Id,
sbs.SpellBook_Id,
sbs.Spell_Id,
Spell = new
{
sbs.Spell_Id,
sbs.Spell.Name,
sbs.Spell.Level,
sbs.Spell.Classes
}
};
如果您想将其序列化为匿名类型,DTO或原始实体,那么现在由您决定。
如果它是第一个选项,那么你就完成了。使用DTO,您应该将DTO类名称添加到查询中:
var spellData = from sbs in db.SpellBookSpells
where sbs.SpellBook_Id == id
select new SpellBookSpellDto
{
sbs.Id,
sbs.SpellBook_Id,
sbs.Spell_Id,
Spell = new SpellDto
{
sbs.Spell_Id,
sbs.Spell.Name,
sbs.Spell.Level,
sbs.Spell.Classes
}
};
要获得原始实体,您应该
var spellDataEntities = from sbs in spellData.AsEnumerable()
select new SpellBookSpell
{
sbs.Id,
sbs.SpellBook_Id,
sbs.Spell_Id,
Spell = new Spell
{
sbs.Spell_Id,
sbs.Spell.Name,
sbs.Spell.Level,
sbs.Spell.Classes
}
};
AsEnumerable()
调用是必要的,因为您无法直接在EF LINQ查询(IQueryable
)中创建实体类型。
通过使用其中一个选项,您可以在一个查询中加载所有必需的数据,而不是一个字节。使用Find
,您首先加载一个您不再使用的SpellBook
对象,然后加载SpellbookSpells
懒惰。即使您只从此集合中选择了有限数量的属性,也会首先加载完整的实体。