Map reference property fields to the same table as root class - sqlite

I have the model with reference properties
internal class AstronomycalBody : IAstronomycalBody
{
public long Id { get; set; }
public string Name { get; set; }
public Coord Coord { get; set; }
public long Mass { get; set; }
public double Speed { get; set; }
public IAstronomycalBody CentralObject { get; set; }
}
public class Coord
{
public long X { get; set; }
public long Y { get; set; }
public long Z { get; set; }
}
I want to use mapping like this
internal class AstronomycalBodyContext : DbContext
{
public DbSet<AstronomycalBody> AstronomycalBody { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(DbSettings.ConnectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AstronomycalBody>().Property(p => p.Coord.X).ForSqliteHasColumnName("CoordX");
modelBuilder.Entity<AstronomycalBody>().Property(p => p.Coord.Y).ForSqliteHasColumnName("CoordY");
modelBuilder.Entity<AstronomycalBody>().Property(p => p.Coord.Z).ForSqliteHasColumnName("CoordZ");
modelBuilder.Entity<AstronomycalBody>().Property(p => p.CentralObject.Id).ForSqliteHasColumnName("CentralObjectId");
}
}
to map the model on this table:
Currently, the compiler is throwing this exception...

Your AstronomycalBody is not a valid EF entity model class.
First, EF Core does not support Complex/value types yet, so the Coord member should be expanded in place.
Second, EF does not work with interfaces, so every navigation reference / collection element type should be entity class.
With that being said, not sure how your IAstronomycalBody looks like and how you can implement it (you might need explicit implementation of some members), but the entity class should be like this:
internal class AstronomycalBody //: IAstronomycalBody
{
public long Id { get; set; }
public string Name { get; set; }
//public Coord Coord { get; set; }
public long CoordX { get; set; }
public long CoordY { get; set; }
public long CoordZ { get; set; }
public long Mass { get; set; }
public double Speed { get; set; }
public AstronomycalBody CentralObject { get; set; }
}
Now, since by convention it will generate the exact table shown, simply remove all shown lines in OnModelCreating and you are done.

Related

How to call Db view file in repository pattern?

I am creating a view file in SQL Server as shown in the image below.
and I created a model to get results from this view:
public class FactALLCousumption : BaseEntity, IAggregateRoot
{
public double sumActiveImportTotal { get; set; }
public DateTime hour { get; set; }
public int fullDateAlternateKey { get; set; }
}
But I can't call this view in my repository. My repository code is bellow:
public class FactCousumptionRepository: GenericRepository<FactCousumption>, IFactCousumptionRepository
{
public DbContext _dbContext;
public FactCousumptionRepository(BaseDbContext context) : base(context)
{
_dbContext = context;
}
public async Task<FactALLCousumption> GetTotalAllCousumption()
{
}
}
In EF Core 2.2 or 2.1, you could use Query types.
According to the screenshot and the model to be used for the View you provided , I make a simple working demo like below , you could refer to and make the modification as per your demand:
1.Model
public class FactCousumption
{
public int Id { get; set; }
public double SumActiveImportTotal { get; set; }
public int DateKeyId { get; set; }
[ForeignKey("DateKeyId")]
public Dim_Date Dim_Date { get; set; }
public int TimeAltKeyId { get; set; }
[ForeignKey("TimeAltKeyId")]
public Dim_Time Dim_Time { get; set; }
public int TariffKeyId { get; set; }
[ForeignKey("TariffKeyId")]
public Dim_Tariff Dim_Tariff { get; set; }
}
public class Dim_Date
{
[Key]
public int DateKey { get; set; }
public int FullDateAlternateKey { get; set; }
public DateTime Date { get; set; }
public ICollection<FactCousumption> FactCousumptions { get; set; }
}
public class Dim_Time
{
[Key]
public int TimeAltKey { get; set; }
public DateTime Hour { get; set; }
public ICollection<FactCousumption> FactCousumptions { get; set; }
}
public class Dim_Tariff
{
[Key]
public int TariffType { get; set; }
public string TariffName { get; set; }
public ICollection<FactCousumption> FactCousumptions { get; set; }
}
2.Create SQL View
CREATE VIEW [dbo].[View1]
AS SELECT SUM(FactCousumption.SumActiveImportTotal) AS consumption ,Dim_Time.HOUR,Dim_Date.FullDateAlternateKey,Dim_Tariff.TariffName
FROM FactCousumption INNER JOIN
Dim_Date ON FactCousumption.DateKeyId = Dim_Date.DateKey INNER JOIN
Dim_Time ON FactCousumption.TimeAltKeyId=Dim_Time.TimeAltKey INNER JOIN
Dim_Tariff ON FactCousumption.TariffKeyId=Dim_Tariff.TariffType
GROUP BY Dim_Date.FullDateAlternateKey, Dim_Time.HOUR ,Dim_Tariff.TariffName
3.The model that is used for the view , note : the property name in model should be consistent with those in the view
public class FactALLCousumption
{
public double consumption { get; set; }
public DateTime hour { get; set; }
public int fullDateAlternateKey { get; set; }
}
4.DbContext , create a DbQuery property in my DbContext to consume the view results inside the Model and set up the View especially if you have different view name than your Class.
public DbQuery<FactALLCousumption> FactALLCousumption { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Query<FactALLCousumption>().ToView("View1");
}
5.Finally you can easily get the results of the View like this.
public async Task<FactALLCousumption> GetTotalAllCousumption()
{
var result = await _context.FactALLCousumption.FirstOrDefaultAsync();
return result;
}
Note: It's worth noting that DbQuery won't be/is not supported anymore in EF Core 3.0. See here

How to include multiple child objects?

I'm playing with new ASP.Net 5.0 WebApi and strugling to understand how to return more then one child object, or child of the child.
Lets say I have 4 classes:
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public int ColourId { get; set; }
public virtual Type Type { get; set; }
public virtual Colour Colour { get; set; }
}
public class Type
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeGroupId { get; set; }
public virtual TypeGroup TypeGroup { get; set; }
}
public class Colour
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TypeGroup
{
public int Id { get; set; }
public string Name { get; set; }
}
And would like to return all the data for the car including Type, Colour, and even TypeGroup of the Type. How do I Do it?
When I do like this it includes only Type:
[HttpGet]
public IEnumerable<Car> Get()
{
return _dbContext.Cars.Include(c => c.Type);
}
This is my setup in Startup.cs:
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
Is it possible to set to return every child object and grandchild and etc?
Many thanks
You can turn off lazy loading for all entities by using the following in your DbContext class (place this in the constructor):
this.Configuration.LazyLoadingEnabled = false;
This will disable it for all entities - so be wary of this and watch for performance issues.
Another way you can load all the entities for a particular class is to remove the virtual keyword from the property declarations.

Foreign key relationship

I'm trying to setup a foreign key using the following two classes.
I want to use pAcqType as an enum and store the names of the types in another table. How should I setup my classes to do this?
public class Property
{
[Key]
public int pID { get; set; }
public string pAddress { get; set; }
public string pCounty { get; set; }
public string pCity { get; set; }
public string pState { get; set; }
public string pzip { get; set; }
public virtual PropertyAcquisitionType pAcqType { get; set; } <-- foreign key
}
public class PropertyAcquisitionType
{
[Key]
public int patID { get; set; }
public string patName { get; set; }
}
UPDATE
Dan got me thinking. And I tried the following and it seems to have worked out.
It setup the foreign key on the table like I wanted. And it didn't even ask for an inverse on the other table.
public int? pAcqType { get; set; }
[ForeignKey("pAcqType")]
public PropertyAcquisitionType patID { get; set; }
Is the foreign key required (NOT NULL in the database)?
public int pAcqTypeId { get; set; }
[ForeignKey("pAcqTypeId")]
public virtual PropertyAcquisitionType pAcqType { get; set; }
Otherwise,
public int? pAcqTypeId { get; set; }
[ForeignKey("pAcqTypeId")]
public virtual PropertyAcquisitionType pAcqType { get; set; }
Then in your other class, add an inverse relationship:
public class PropertyAcquisitionType
{
[Key]
public int patID { get; set; }
public string patName { get; set; }
[InverseProperty("pAcqType")]
public virtual ICollection<Property> pOfThisType { get; set; }
}
Here is one way you could define the relationship using the fluent API (without attributes in the entity classes). Note with this method, you should not need to add a properties property on the PropertyAcquisitionType entity to satisfy the inverse side of the relationship, because the .WithMany() tells EF what it needs to know:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Property>()
.HasKey(x => x.pID)
.HasRequired(x => x.pAcqType) // or HasOptional if using int?
.WithMany() // or WithMany(x => x.pOfThisType) if you want to add / keep the inverse property
.HasForeignKey(x => x.pAcqTypeId)
;
}
}

AutoMpper + Map Complex Nested Many to Many Relationship

I have domain model like this
public class EntityOne
{
public int EnityOneId { get; set; }
public int EntityOnePropertyOne { get; set; }
public List<EntityTwo> EntityTwos { get; set; }
}
public class EntityTwo
{
public int EntityTwoId { get; set; }
public string EntityTwoPropertyOne { get; set; }
public int EntityThreeId { get; set; }
public int EnityOneId { get; set; }
public virtual EntityOne EntityOne { get; set; }
public virtual EntityThree EntityThree { get; set; }
}
public class EntityThree
{
public int EntityThreeId { get; set; }
public string EntityThreePropertyOne { get; set; }
}
and I have DTO like this
public class EntityDTO
{
public int EntityOnePropertyOne { get; set; }
public string EntityThreePropertyOne_ValueOne { get; set; }
public string EntityThreePropertyOne_ValueTwo { get; set; }
public string EntityThreePropertyOne_ValueThree { get; set; }
public string EntityThreePropertyOne_ValueFour { get; set; }
public string EntityThreePropertyOne_ValueFive { get; set; }
}
I want to configure mapping from DTO to DomainModel and the reverse using AutoMapper but I didnt know how to do that... any suggestion or help
I'm not sure what you're trying to accomplish here.
I get that you want to map to EntityDTO, but from what other type? I will assume you want to use EntityTwo as the source.
In that case,
EntityOnePropertyOne: Will be obtained automatically via Flattening from the source (EntityTwo) - So, no problem here.
EntityThreePropertyOne_ValueOne: This will assume you have a property called EntityThree (which you do), and within that type, a property called PropertyOne_ValueOne of type int (which you don't). Same applies for the rest.
The other way around will get trickier, since I see there will be lots of properties ignored, so you need to tell AutoMapper, that you don't want it to be concerned about all that bunch of properties in your complex type, that don't come from the DTO.

Entity Framework WebApi Circular dependency serialization error

I think, I've read everything about this error and I tried everything. Here are my models:
Main:
public class Trip
{
public int TripId { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string Country { get; set; }
public float BasicPrice { get; set; }
public virtual ICollection<ApartmentType> ApartmentType { get; set; }
public virtual ICollection<TransportMethod> TransportMethod { get; set; }
public virtual ICollection<FeedingType> FeedingType { get; set; }
}
ApartmentType:
public class TransportMethod
{
public int TransportMethodId { get; set; }
public int TripId { get; set; }
public string Name { get; set; }
public float Price { get; set; }
}
FeedingType:
public class FeedingType
{
public int FeedingTypeId { get; set; }
public int TripId { get; set; }
public string Description { get; set; }
public float Price { get; set; }
}
TransportType:
public class TransportMethod
{
public int TransportMethodId { get; set; }
public int TripId { get; set; }
public string Name { get; set; }
public float Price { get; set; }
}
When serializng the Trip entity I get a circular dependency error. Things i tried:
Disable lazy loading in DbContext.
Adding
json.SerializerSettings.PreserveReferencesHandling=Newtonsoft.Json.PreserveReferencesHandling.All; to GLobal.asax
Adding a decorator [IgnoreDataMember] to TripId in every child entity.
Mapping this entity to a ViewModel which doesn't contain the ICollection members. - This worked ok, but at some point I will want to get those lists to the client.
I really don't know what's going on. What am I missing? I really can't spot any circular dependency.
Have you tried adding the [JsonIgnore] attribute to the TripId to the children entities?
http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonIgnoreAttribute.htm
or setting
json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

Resources