Is there a way to join tables by multiple columns? - ormlite-servicestack

I can join by a single property
var sql = new JoinSqlBuilder<ClassA, ClassB>().Join<ClassA, ClassB>(src => src.PropA, dst => dst.PropA);
I don't see a way to join by multiple properties though. Pretty sure there's no way to do that yet, but want to double-check.

The join class in joinbuilder only has one class/column name, so it seems pretty certain there is no way using default join builder.
class Join
{
public Type Class1Type { get; set; }
public Type Class2Type { get; set; }
public Type RefType { get; set; }
public JoinType JoinType { get; set; }
public string Class1Schema { get; set; }
public string Class2Schema { get; set; }
public string Class1TableName { get; set; }
public string Class2TableName { get; set; }
public string RefTypeSchema { get; set; }
public string RefTypeTableName { get; set; }
public string Class1ColumnName { get; set; }
public string Class2ColumnName { get; set; }
}

Related

Translate LINQ to LAMBDA Entity Framework Core using INCLUDE (NOT JOIN)

How to call multiple entities using Include method (not Join method) in Entity Framework Core? I am trying to translate this LINQ query to EF Core 5 syntax, but I do not know how to call multiple entities and join them together using include method.
var reservations = from reservation in _dbContext.Reservations
join customer in _dbContext.Users on reservation.UserId equals customer.Id
join movie in _dbContext.Movies on reservation.MovieId equals movie.Id
select new
{
Id = reservation.Id,
ReservationTime = reservation.ReservationTime,
CustomerName = customer.Id,
MovieName = movie.Name
};
I tried using multiple include and select method, but do not know how to call multiple entities and join
Here are my models
public class Reservation
{
public int Id { get; set; }
public int Qty { get; set; }
public double Price { get; set; }
public string Phone { get; set; }
public DateTime ReservationTime { get; set; }
public int MovieId { get; set; }
public int UserId { get; set; }
}
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Language { get; set; }
public string Duration { get; set; }
public DateTime PlayingDate { get; set; }
public DateTime PlayingTime { get; set; }
public double TicketPrice { get; set; }
public double Rating { get; set; }
public string Genre { get; set; }
public string TrailorUrl { get; set; }
public string ImageUrl { get; set; }
[NotMapped]
public IFormFile Image { get; set; }
public ICollection<Reservation> Reservations { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Role { get; set; }
public ICollection<Reservation> Reservations { get; set; }
}
Controller code:
var reservations = _dbContext.Reservations
.Include(r => r.Id)
.Include(c => c.User)
.Select(x => new { x.Id, x.ReservationTime, x.User, x.User.Name });
If add to Reservation navigation properties Movie and User, your query can be simplified. Include cannot be used with Select together, it is ignored by EF translator.
var reservations = _dbContext.Reservations
.Select(r => new
{
Id = r.Id,
ReservationTime = r.ReservationTime,
CustomerName = r.User.Id,
MovieName = r.Movie.Name
});

Is it possible to get List<T> without some objects?

Need to get all data from List without status and date
public class Locations
{
public string CompanyCode { get; set; }
public string SupplierId { get; set; }
public string LocationName { get; set; }
public int Status { get; set; }
public DteTime date{ get; set; }
public int ResultCode { get; set; }
public string ResultMessage { get; set; }
}
I getting all locations in below list, I want to avoid status and date from the results
List<Locations> results
You could make use Anonymous Types
results.Select(x=>new{x.CompanyCode,x.SupplierId,x.LocationName,x.ResultCode,x.ResultMessage})
Alternatively, you could create a Custom class with only the desired property and project it using Linq as shown in the example with Anonymous Types
or you can use deriving from class/interface and then cast to it ;)
you can do something like this:
public interface ILocationsPoorData
{
public string CompanyCode { get; set; }
public string SupplierId { get; set; }
public string LocationName { get; set; }
public int ResultCode { get; set; }
public string ResultMessage { get; set; }
}
class Locations:ILocationsPoorData
{
public string CompanyCode { get; set; }
public string SupplierId { get; set; }
public string LocationName { get; set; }
public int Status { get; set; }
public DteTime date{ get; set; }
public int ResultCode { get; set; }
public string ResultMessage { get; set; }
}
and in the end, when you'll have list of locations, you can do sth like this:
var newList = locationsList.select(x=> x as ILocationsPoorData)
or
var newList = locationsList.Cast<ILocationsPoorData>();
or you can create class instead of interface and do the same ;)
or you can use anonymous types like in previous answer
or you can create some value tuple instead of anonymous types ;)

ServiceStack AutoQuery join use

After reading the documentation, I am not sure but I have come to the conclusion that when creating QueryDb, you cannot choose the columns to join by? And I am under the impression, you must have DTO object to copy to? You cannot copy to a regular object or a dynamic object?
public class SampleAutoQueryDb : QueryDb<MailResponseDetailOrm, object>, ILeftJoin<MailResponseDetailOrm, MailResponseOrm> { }
Can anyone provide any insight on joining my MailResponseOrm to MailResponseDetailOrm. MailResponseDetailOrm has 5 fields namely the Email address. And I would like MailResponseOrm to be joined to it by Email as well. I also, for good measure do not want to alter either columnname. Would I have to create a custom implementation or a service to do this?
UPDATE
Here is my code as posted below:
[Alias("MailReportsDetail")]
public class MailResponseDetailOrm
{
public string Email { get; set; }
public int ID { get; set; }
[Alias("RespDate")]
public DateTime? AddedDateTime { get; set; }
[Alias("DLReport")]
public string Action { get; set; }
public string ActionDetail { get; set; }
public string IP { get; set; }
public string UserAgent { get; set; }
public string EmailReferrer { get; set; }
}
[Alias("MailReports")]
public class MailResponseOrm
{
public int ID { get; set; }
public string Email { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string Company { get; set; }
public string Contact { get; set; }
public string Country { get; set; }
[Alias("LastMail")]
public DateTime? ModifiedDateTime { get; set; }
[Alias("LastReport")]
public string Action { get; set; }
public DateTime? OptOut { get; set; }
public string Part { get; set; }
public string Phone { get; set; }
public string PostalCode { get; set; }
public string Source { get; set; }
public string State { get; set; }
public string Title { get; set; }
#region Obsolete
[Obsolete]
public string Class { get; set; }
[Obsolete]
public string IP { get; set; }
#endregion
}
public class SampleAutoQueryDb : QueryDb<MailResponseDetailOrm> { }
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
// Override with custom implementation
public object Any(SampleAutoQueryDb query)
{
var q = AutoQuery.CreateQuery(query, base.Request);
q.Join<MailResponseDetailOrm, MailResponseOrm>((x, y) => x.Email == y.Email)
// .Select<MailResponseDetailOrm, MailResponseOrm>((x, y) => new { x.ID, y.Email })
;
return AutoQuery.Execute(query, q);
}
}
Joins in AutoQuery needs to use OrmLite's Joins Reference conventions and all AutoQuery Services results are returned in a Typed DTO, which by default is the table being queried or you can use the QueryDb<From,Into> base class to return a custom result of columns from multiple joined tables.
You would need to use a Custom AutoQuery Implementation or your own Service implementation if you need customizations beyond this, e.g:
public class SampleAutoQueryDb : QueryDb<MailResponseDetailOrm> { }
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
// Override with custom implementation
public object Any(SampleAutoQueryDb query)
{
var q = AutoQuery.CreateQuery(query, base.Request);
q.Join<MailResponseDetailOrm,MailResponseOrm>((x, y) => x.Email == y.Email);
return AutoQuery.Execute(query, q);
}
}
// The query to join 2 objects on field names not specifically set in the class.
var q = Db.From<MailResponseDetailOrm>().Join<MailResponseDetailOrm>(x,y) => x.Email = y.Email);
// Run the query
var results = Db.Select(q);

EF6 MVC5 Setting a 1-1 Relationship

I have got my application up and running using Code first, I am trying to set a 1-1 relationship but when I update-database I get the error "SupplyPointId: Name: Each property name in a type must be unique. Property name 'SupplyPointId' is already defined."
I've tried removing the existing index constraint on SupplyPointAddress.SupplyPointId and that does not help. In the other table its the PK. Any comments really appreciated
public partial class SupplyPoint
{
[Key]
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int SupplyPointId { get; set; }
public string SPID { get; set; }
public string SupplyPointName { get; set; }
public int SupplyPointTypeId { get; set; }
public DateTime SupplyPointEffectiveDateTime { get; set; }
public string GazateerRef { get; set; }
public virtual SupplyPointType SupplyPointType { get; set; }
//[ForeignKey("SupplyPointId")]
public virtual SupplyPointAddress SupplyPointAddress { get; set; }
}
public partial class SupplyPointAddress
{
[Key]
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int SupplyPointAddressId { get; set; }
public int SupplyPointId { get; set; }
public string D5001_FreeDescriptor { get; set; }
public string D5002_SubBuildingName { get; set; }
public string D5003_BuildingName { get; set; }
public string D5004_BuildingNumber { get; set; }
public string D5005_DependentThoroughfareName { get; set; }
public string D5006_DependentThoroughfareDescriptor { get; set; }
public string D5007_ThoroughfareName { get; set; }
public string D5008_ThoroughfareDescriptor { get; set; }
public string D5009_DoubleDependentLocality { get; set; }
public string D5010_DependentLocality { get; set; }
public string D5011_PostTown { get; set; }
public string D5012_County { get; set; }
public string D5013_Postcode { get; set; }
public virtual SupplyPoint SupplyPoint { get; set; }
}
public System.Data.Entity.DbSet<AscendancyCF.Models.SupplyPoint> SupplyPoints { get; set; }
public System.Data.Entity.DbSet<AscendancyCF.Models.SupplyPointAddress> SupplyPointAddresses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SupplyPointAddress>()
.HasOptional<SupplyPoint>(u => u.SupplyPoint)
.WithRequired(c => c.SupplyPointAddress).Map(p => p.MapKey("SupplyPointId"));
base.OnModelCreating(modelBuilder);
}
I moved the foreign key into SupplyPoint table so that the foreign key was being defined as SupplyPointAddressId in SupplyPoint. This worked and allows me to do SupplyPoint.SupplyPointAddress in resultant model
Since you're testing with a real DB. Use some of the
Database Initialization Strategies in Code-First:
public class SchoolDBContext: DbContext
{
public SchoolDBContext(): base("SchoolDBConnectionString")
{
Database.SetInitializer<SchoolDBContext>(new CreateDatabaseIfNotExists<SchoolDBContext>());
//Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseIfModelChanges<SchoolDBContext>());
//Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseAlways<SchoolDBContext>());
//Database.SetInitializer<SchoolDBContext>(new SchoolDBInitializer());
}
public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; }
}
(Excerpt from this site)
It is pretty self explanatory.
If there's already a DB created, it just DROPs it.
Happy coding!

MVC4 EF5 entity property not updating on SaveChanges()

I've been reading through lots of articles trying to learn MVC4, but I'm stumped as to why my entity is not getting updated to database.
I've been trying to modify the MVC4 VS2012 Internet template.
So, here's the Controller action:
[HttpPost, ActionName("Approve")]
[Authorize]
public ActionResult ApproveConfirmed(long id)
{
using (StudentiContext context = new StudentiContext())
{
// context.Configuration.AutoDetectChangesEnabled = false;
var studente = (from d in context.STUDENTI_STRANIERI_MASTER_REG
where d.ID_PERSONA == id
select d).Single();
STUDENTI_STRANIERI_MASTER_REG st2 = studente;
st2.ESITO = 1;
//studente.ESITO = 1;
var statos = context.Entry(studente).State;
Console.WriteLine("Before DetectChanges: {0}",statos);
//context.ChangeTracker.DetectChanges();
context.Entry(studente).State = EntityState.Modified;
context.Entry(studente).CurrentValues.SetValues(st2);
// var tracked = context.ChangeTracker.Entries();
context.Entry(studente).Property( o => o.ESITO ).IsModified = true;
TryUpdateModel(studente);
context.SaveChanges();
Console.WriteLine("After DetectChanges: {0}",statos);
return RedirectToAction("PrivateIndex");
}
}
The aim is just to update one property, ESITO and set it to 1. Currently its value is 2.
This is the model:
namespace MvcStudenti2.Models
{
using System;
using System.Collections.Generic;
public partial class STUDENTI_STRANIERI_MASTER_REG
{
public long ID_PERSONA { get; set; }
public string COGNOME { get; set; }
public string NOME { get; set; }
public string SESSO { get; set; }
public System.DateTime DATA_NASCITA { get; set; }
public long ID_STATO_NASCITA { get; set; }
public string LUOGO_NASCITA_ESTERO { get; set; }
public string CODICE_FISCALE { get; set; }
public string TITOLO_POSSEDUTO { get; set; }
public Nullable<short> DURATA_TITOLO { get; set; }
public string VOTAZIONE { get; set; }
public string UNI_PROVENIENZA { get; set; }
public long ID_STATO_UNI { get; set; }
public string CERT_LINGUISTICA { get; set; }
public string CERT_PUNTEGGIO { get; set; }
public string NOTE { get; set; }
public System.DateTime DATA_RICHIESTA { get; set; }
public short ESITO { get; set; }
public string CDS_COD { get; set; }
public string EMAIL { get; set; }
public string NUMERO_TELEFONO { get; set; }
public string INDIRIZZO { get; set; }
public string CAP_INDIRIZZO { get; set; }
public string CITTA { get; set; }
public long ID_STATO_INDIRIZZO { get; set; }
public string DESCRIZIONE_CIT_NAZ { get; set; }
public Nullable<System.DateTime> DATA_COMPLETAMENTO_ATTESO { get; set; }
public Nullable<System.DateTime> ANNO_COMPLETAMENTO { get; set; }
public Nullable<short> DURATA_CORSO_COMPLETATO { get; set; }
public decimal GPA { get; set; }
public string ALTRI_TITOLI { get; set; }
public string MADRELINGUA { get; set; }
public Nullable<short> CERT_TOEFL_PUNT { get; set; }
public string CERT_FIRSTCERT_GRADE { get; set; }
public Nullable<short> CERT_FIRSTCERT_PUNT { get; set; }
public byte[] FILE_CV { get; set; }
public byte[] FILE_CARRIERA { get; set; }
public byte[] FILE_CERT_LINGUA { get; set; }
public byte[] FILE_DOC_IDENTITA { get; set; }
public string PWD { get; set; }
public string FILE_CV_NOME { get; set; }
public string FILE_CARRIERA_NOME { get; set; }
public string FILE_CERT_LINGUA_NOME { get; set; }
public string FILE_DOC_IDENTITA_NOME { get; set; }
public string FILE_CV_TIPO { get; set; }
public string FILE_CARRIERA_TIPO { get; set; }
public string FILE_CERT_LINGUA_TIPO { get; set; }
public string FILE_DOC_IDENTITA_TIPO { get; set; }
public Nullable<short> STATO { get; set; }
public Nullable<short> VALUTATO { get; set; }
public Nullable<short> ARCHIVIATO { get; set; }
public string CDS_COD_2 { get; set; }
public Nullable<short> MAIL_INVIATA { get; set; }
public string LINK_ULTIMO_CORSO { get; set; }
public Nullable<short> ATTIVO { get; set; }
public byte[] FILE_LETTERA_ACCETTAZIONE { get; set; }
public string FILE_LETTERA_ACCETTAZIONE_NOME { get; set; }
public string FILE_LETTERA_ACCETTAZIONE_TIPO { get; set; }
}
}
Everywhere I read I find that SaveChanges() should be enough, possibly after the EntityState.Modified.
I can correctly edit the entity, if I pass the whole entity to the Action, but in this case the Approve view is a built on a Detail template, so I don't have anything to POST from it (and I'd prefer not to: I could insert a hidden field and post just that, but I'm trying to update a single filed from code, and I'm not sure if the whole entity would get updated or overwritten ).
statos goes to "modified", if I understand correctly, because I have done a query on the entity.
Another thing I don't understand is why ESITO gets update -also- in studente, but then reverts to "2" after SaveChanges().
Are property changes being detected? I've wrapped every Action in a using block, as suggested elsewhere, so not to have multiple contextx/instances around.
Could anyone please point me to what I'm doing wrong? The code above is probably over-redundant, but I've been trying everything I have found on SO.
Thanks, everyone.
The following is all that is required to change the ESITO property.
[HttpPost, ActionName("Approve")]
[Authorize]
public ActionResult ApproveConfirmed(long id)
{
using (StudentiContext context = new StudentiContext())
{
// context.Configuration.AutoDetectChangesEnabled = false;
var studente = (from d in context.STUDENTI_STRANIERI_MASTER_REG
where d.ID_PERSONA == id
select d).Single();
studente.ESITO = 1;
context.SaveChanges();
return RedirectToAction("PrivateIndex");
}
}

Resources