using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using ServiceStack.DataAnnotations;
using ServiceStack.Model;
using ServiceStack.Text;

namespace ServiceStack.OrmLite.Tests.Issues
{
    [TestFixtureOrmLite]
    public class AdhocJoinIssue : OrmLiteProvidersTestBase
    {
        public AdhocJoinIssue(DialectContext context) : base(context) {}

        [Test]
        public void Can_run_LRA_Query()
        {
            using (var db = OpenDbConnection())
            {
                CreateTables(db);

                var query = db.From<LRAAnalisi>()
                    .Join<LRAAnalisi, LRAContenitore>((ana, cont) => ana.ContenitoreId == cont.Id)
                    .Join<LRAContenitore, LRARichiesta>((cont, ric) => cont.RichiestaId == ric.Id)
                    .Join<LRARichiesta, LRAPaziente>((ric, paz) => ric.PazienteId == paz.Id)
                    .Select<LRAAnalisi, LRAContenitore, LRARichiesta, LRAPaziente>((ana, cont, ric, paz) =>
                        new
                        {
                            AnalisiId = ana.Id,
                            ContenitoreId = cont.Id,
                            RichiestaId = ric.Id,
                            DataAccettazioneRichiesta = ric.DataOraAccettazione,
                            DataCheckinContenitore = cont.DataOraPrimoCheckin,
                            DataEsecuzioneAnalisi = ana.DataOraEsecuzione,
                            DataPrelievoContenitore = cont.DataOraPrelievo,
                            DataValidazioneAnalisi = ana.DataOraValidazione,
                            sessoPaziente = paz.Sesso,
                            dataDiNascitaPaziente = paz.DataDiNascita,
                            etaPazienteRichiesta = ric.EtaPaziente,
                            dataOraAccettazioneRichiesta = ric.DataOraAccettazione,
                            unitaMisuraEtaPaziente = ric.UnitaDiMisuraEtaPaziente,
                            settimaneGravidanza = ric.SettimaneGravidanza,
                            repartoId = ric.RepartoId,
                            prioritaRichiesta = ric.PrioritaId,
                            laboratorioRichiedente = ric.LaboratorioRichiedenteId,
                            prioritaContenitore = cont.PrioritaId,
                            idLaboratorioEsecutoreCandidatoAnalisi = ana.LaboratorioEsecutoreCandidatoId
                        });
            }
        }

        [Test]
        public void Can_run_expression_using_captured_lambda_params()
        {
            using (var db = OpenDbConnection())
            {
                CreateTables(db);

                var idContenitore = 1;
                
                var q = db.From<LRAAnalisi>()
                    .Where(ana => ana.ContenitoreId == idContenitore)
                    .And(ana => !Sql.In(ana.Id, db.From<LRAContenitore>()
                            .Where(ris => ris.Id == ana.ContenitoreId)
                            .Select(ris => new { Id = ris.Id })
                        )
                    )
                    .Select(x => new { A = 1 });

                var sql = q.ToSelectStatement();
                sql.Print();
                Assert.That(sql, Is.Not.Null);
            }
        }
        
        [Test]
        public void Does_select_aliases_on_custom_expressions()
        {
            var statements = new List<string>();
            OrmLiteConfig.BeforeExecFilter = cmd => statements.Add(cmd.GetDebugString());

            using (var db = OpenDbConnection())
            {
                var ADeviceId = 1;
                
                var q = db.From<LRDDevice>();
                q.LeftJoin<LRDDevice,LRDConnessione>((a,b)=>a.Id==b.DeviceId);
                q.LeftJoin<LRDDevice, LRAAlert>((a, b) => a.Id == b.DeviceID && b.Visto==(int)SiNo.No);
                q.Where<LRDDevice>(x => x.Id == ADeviceId);
                q.GroupBy<LRDDevice,LRDConnessione, LRAAlert>((dev,con, ale) => new {dev.Id, con.DeviceId, ale.DeviceID,ale.Tipo });
                q.Select<LRDDevice, LRDConnessione, LRAAlert>((dev, con, ale) => new //DeviceDashboardDTO
                {
                    DeviceId = dev.Id,
                    //Device = dev,
                    StatoLinea = Sql.Min(con.StatoConnessione),
                    StatoQC = (Sql.Count(ale.Tipo == (int)TipoAlert.AlertQC ? ale.Id : 0) > 0 ? (int)SiNo.Si : (int)SiNo.No),
                    StatoWarning = (Sql.Count(ale.Tipo == (int)TipoAlert.WarningDevice ? ale.Id : 0) > 0 ? (int)SiNo.Si : (int)SiNo.No)
                });


                try
                {
                    var results = db.Select<DeviceDashboardDTO>(q);
                }
                catch {} // no tables

                var lastStatement = statements.Last();
                lastStatement.Print();
                
                lastStatement = lastStatement.NormalizeSql();
                Assert.That(lastStatement, Does.Contain("as deviceid"));
                Assert.That(lastStatement, Does.Contain("as statolinea"));
                Assert.That(lastStatement, Does.Contain("as statoqc"));
                Assert.That(lastStatement, Does.Contain("as statowarning"));
            }
        }

        [Test]
        public async Task Does_RowCount_LRARichiesta_Async()
        {
            using (var db = OpenDbConnection())
            {
               CreateTables(db);
                
                var q = db.From<LRARichiesta>()
                    .Where(x => x.Id > 0);

                var result = await db.RowCountAsync(q);                
            }
        }

        [Test]
        public void Does_InsertIntoSelect_LRARichiesta()
        {            
            using (var db = OpenDbConnection())
            {
                RecreateLRARichiesta(db);

                long numeroRichieste = db.Count<LRARichiesta>();

                var q = db.From<LRARichiesta>()
                    .Select(ric => new //LRARisultato
                    {
                        AnalisiId = 1,
                        Commento = ric.Commento,
                        TipoValore = 1,
                        Stato = 1,
                        RisultatoId = 1,
                        DataOraRicezione = DateTime.UtcNow,
                        DataModifica = DateTime.UtcNow,
                        VersioneRecord = 1,
                        InviareALIS = 1,
                        RisultatoPrincipale = 1,
                        TipoInserimento = 1,
                        Citrato = 1,
                    });

                long result = db.InsertIntoSelect<LRARisultato>(q);

                Assert.That(result, Is.EqualTo(numeroRichieste));
            }
        }

        private static void RecreateLRARichiesta(IDbConnection db)
        {
            db.DropTable<LRAAnalisi>();
            db.DropTable<LRAContenitore>();
            db.DropTable<LRARichiesta>();
            db.DropTable<LRARisultato>();
            db.DropTable<LRDLaboratorio>();
            db.DropTable<LRAPaziente>();
            db.DropTable<LRDReparto>();
            db.DropTable<LRDPriorita>();

            db.CreateTable<LRDLaboratorio>();
            db.CreateTable<LRAPaziente>();
            db.CreateTable<LRDReparto>();
            db.CreateTable<LRDPriorita>();
            db.CreateTable<LRARisultato>();
            db.CreateTable<LRARichiesta>();
            db.CreateTable<LRAContenitore>();
            db.CreateTable<LRAAnalisi>();
        }

        [Test]
        public async Task Does_InsertIntoSelect_LRARichiesta_Async()
        {            
            using (var db = OpenDbConnection())
            {
                RecreateLRARichiesta(db);

                long numeroRichieste = await db.CountAsync<LRARichiesta>();

                var q = db.From<LRARichiesta>()
                    .Select(ric => new //LRARisultato
                    {
                        AnalisiId = 1,
                        Commento = ric.Commento,
                        TipoValore = 1,
                        Stato = 1,
                        RisultatoId = 1,
                        DataOraRicezione = DateTime.UtcNow,
                        DataModifica = DateTime.UtcNow,
                        VersioneRecord = 1,
                        InviareALIS = 1,
                        RisultatoPrincipale = 1,
                        TipoInserimento = 1,
                        Citrato = 1,
                    });

                long result = await db.InsertIntoSelectAsync<LRARisultato>(q);

                Assert.That(result, Is.EqualTo(numeroRichieste));
            }
        }
        
        private static void CreateTables(IDbConnection db)
        {
            DropTables(db);

            db.CreateTable<LRARisultato>();
            db.CreateTable<LRDLaboratorio>();
            db.CreateTable<LRDPriorita>();
            db.CreateTable<LRDReparto>();
            db.CreateTable<LRAPaziente>();
            db.CreateTable<LRARichiesta>();
            db.CreateTable<LRAContenitore>();
            db.CreateTable<LRAAnalisi>();
        }

        private static void DropTables(IDbConnection db)
        {
            db.DropTable<LRAAnalisi>();
            db.DropTable<LRAContenitore>();
            db.DropTable<LRARichiesta>();
            db.DropTable<LRAPaziente>();
            db.DropTable<LRDReparto>();
            db.DropTable<LRDPriorita>();
            db.DropTable<LRDLaboratorio>();
            db.DropTable<LRARisultato>();
        }

        private static void InitAliasTables(IDbConnection db)
        {
            db.DropTable<LRDProfiloAnalisi>();
            db.DropTable<LRDAnalisi>();
            db.DropTable<LRDContenitore>();
                
            db.CreateTable<LRDContenitore>();
            db.CreateTable<LRDAnalisi>();
            db.CreateTable<LRDProfiloAnalisi>();

            db.Insert(new LRDAnalisi
            {
                Codice = "TEST", 
                Descrizione = "DESCRIPTION",
                DataModifica = DateTime.UtcNow
            });

            db.Insert(new LRDProfiloAnalisi
            {
                AnalisiId = 1,
                DataModifica = DateTime.UtcNow,
                VersioneRecord = 1,
                ProfiloAnalisiId = null
            });
        }
        
        [Test]
        public void Table_Alias()
        {
            using (var db = OpenDbConnection())
            {
                InitAliasTables(db);
                
                var q = db.From<LRDAnalisi>(options => {
                        options.SetTableAlias("dana");
                        options.UseSelectPropertiesAsAliases = true;
                    })
                    .Join<LRDAnalisi, LRDContenitore>((dana, dcont) => dana.ContenitoreId == dcont.Id, db.TableAlias("c"))
                    .Join<LRDAnalisi, LRDProfiloAnalisi>((dana, dprofana) => dana.Id == dprofana.AnalisiId, db.TableAlias("dprofana"))
                    .Where<LRDProfiloAnalisi>(dprofana => Sql.TableAlias(dprofana.ProfiloAnalisiId, "dprofana") == null)
                    .SelectDistinct<LRDAnalisi, LRDProfiloAnalisi, LRDContenitore>((dana, dprofana, dcont) =>
                        new //ProfiloAnalisiDTO
                        {
                            Id = Sql.TableAlias(dprofana.Id, "dprofana"),
                            AnalisiId = dana.Id,
                            Codice = dana.Codice,
                            Descrizione = dana.Descrizione,
                            ContenitoreId = dana.ContenitoreId,
                            ContenitoreCodice = Sql.TableAlias(dcont.Codice, "c"),
                            ContenitoreDescrizione = Sql.TableAlias(dcont.Descrizione, "c"),
                            VersioneRecord = Sql.TableAlias(dprofana.VersioneRecord, "dprofana")
                        });
                
                var result = db.Select<ProfiloAnalisiDTO>(q);
            }
        }
        
        [Test]
        public void Join_Alias()
        {
            using (var db = OpenDbConnection())
            {
                InitAliasTables(db);

                var q = db.From<LRDAnalisi>()
                    .Join<LRDAnalisi, LRDContenitore>((dana, dcont) => dana.ContenitoreId == dcont.Id, db.JoinAlias("c"))
                    .Join<LRDAnalisi, LRDProfiloAnalisi>((dana, dprofana) => dana.Id == dprofana.AnalisiId, db.JoinAlias("dprofana"))
                    .Where<LRDProfiloAnalisi>(dprofana => Sql.JoinAlias(dprofana.ProfiloAnalisiId, "dprofana") == null)
                    .SelectDistinct<LRDAnalisi, LRDProfiloAnalisi, LRDContenitore>((dana, dprofana, dcont) =>
                        new //ProfiloAnalisiDTO
                        {
                            Id = Sql.JoinAlias(dprofana.Id, "dprofana"),
                            AnalisiId = dana.Id,
                            Codice = dana.Codice,
                            Descrizione = dana.Descrizione,
                            ContenitoreId = Sql.JoinAlias(dcont.Id, "c"),
                            ContenitoreCodice = Sql.JoinAlias(dcont.Codice, "c"),
                            ContenitoreDescrizione = Sql.JoinAlias(dcont.Descrizione, "c"),
                            VersioneRecord = Sql.JoinAlias(dprofana.VersioneRecord, "dprofana")
                        });
                
                var result = db.Select<ProfiloAnalisiDTO>(q);
            }
        }        
    }
    
    public class ElementoProfiloAnalisiDTO
    {
        public int Id { get; set; }

        public int ProfiloAnalisiId { get; set; }

        public int AnalisiId { get; set; }

        public string CodiceAnalisi { get; set; }

        public string DescrizioneAnalisi { get; set; }

        public int VersioneRecord { get; set; }
    }
    
    public class ProfiloAnalisiDTO
    {
        public int Id { get; set; }

        public string Codice { get; set; }

        public string Descrizione { get; set; }

        public int ContenitoreId { get; set; }

        public string ContenitoreCodice { get; set; }

        public string ContenitoreDescrizione { get; set; }

        public int VersioneRecord { get; set; }

        public int AnalisiId { get; set; }

        public IEnumerable<ElementoProfiloAnalisiDTO> Elementi { get; set; }
    }
    

    public class DBObject : ICloneable
    {
        [Alias("DATAMODIFICA")]
        public DateTime DataModifica { get; set; }

        [Default(1)]
        [Alias("VERSIONERECORD")]
        public int VersioneRecord { get; set; }

        public object Clone()
        {
            return MemberwiseClone();
        }
    }

    public class SessiPaziente
    {
        public const int NonDichiarato = 0;
    }

    public class UnitaMisuraEtaPaziente
    {
        public const int Anni = 0;
    }
    
    [Alias("LRAANALISI")]
    public class LRAAnalisi : IHasId<int>
    {
        [PrimaryKey]
        [AutoIncrement]        
        [Alias("IDAANALISI")]
        public int Id { get; set; }

        [Alias("ACONTENITOREID")]
        [References(typeof(LRAContenitore))]
        public int ContenitoreId { get; set; }

        [Reference]
        public LRAContenitore Contenitore { get; set; }

        [Alias("DATAORAVALIDAZIONE")]
        public DateTime? DataOraValidazione { get; set; }

        [Alias("DLABORATORIOCANDIDATOID")]
        [References(typeof(LRDLaboratorio))]
        public int? LaboratorioEsecutoreCandidatoId { get; set; }

        [Alias("DATAORAESECUZIONE")]
        public DateTime? DataOraEsecuzione { get; set; }
    }
    
    [Alias("LRACONTENITORI")]
    public class LRAContenitore : DBObject, IHasId<int>
    {
        [PrimaryKey]
        [AutoIncrement]
        [Alias("IDACONTENITORE")]
        public int Id { get; set; }

        [Alias("ARICHIESTAID")]
        [References(typeof(LRARichiesta))]
        public int RichiestaId { get; set; }
        
        [Alias("DPRIORITAID")]
        [References(typeof(LRDPriorita))]
        public int PrioritaId { get; set; }

        [Alias("DATAORAPRELIEVO")]
        public DateTime? DataOraPrelievo { get; set; }

        [Alias("DATAORAPRIMOCHECKIN")]
        public DateTime? DataOraPrimoCheckin { get; set; }
    }

    [Alias("LRARICHIESTE")]
    public class LRARichiesta : DBObject, IHasId<int>
    {
        [PrimaryKey]
        [AutoIncrement]
        [Alias("IDARICHIESTA")]                
        public int Id { get; set; }
        
        [Alias("APAZIENTEID")]
        [ForeignKey(typeof(LRAPaziente))]
        public int PazienteId { get; set; }

        [Index(Unique = false)]
        [Alias("DATAORAACCETTAZIONE")]                        
        public DateTime DataOraAccettazione { get; set; }

        [Alias("ETAPAZIENTE")]
        public int? EtaPaziente { get; set; }

        [Alias("UNITADIMISURAETAPAZIENTE")]
        [Default((int) UnitaMisuraEtaPaziente.Anni)]
        public int UnitaDiMisuraEtaPaziente { get; set; }

        [Alias("SETTIMANEGRAVIDANZA")]               
        public int? SettimaneGravidanza { get; set; }
        
        [Alias("DREPARTOID")]
        [References(typeof(LRDReparto))]
        public int? RepartoId { get; set; }
        
        [Required]
        [Alias("DPRIORITAID")]
        [References(typeof(LRDPriorita))]        
        public int PrioritaId { get; set; }

        [Required]
        [References(typeof(LRDLaboratorio))]
        [Alias("DLABORATORIORICHIEDENTEID")]        
        public int? LaboratorioRichiedenteId { get; set; }
        
        [Alias("COMMENTO")]
        [StringLength(StringLengthAttribute.MaxText)]
        public string Commento { get; set; }
    }
    
    [Alias("LRAPAZIENTI")]
    public class LRAPaziente : DBObject, IHasId<int>
    {
        [PrimaryKey]
        [AutoIncrement]
        [Alias("IDAPAZIENTE")]               
        public int Id { get; set; }
               
        [Alias("SESSO")]
        [Default((int) SessiPaziente.NonDichiarato)]
        public int Sesso { get; set; }

        [Alias("DATADINASCITA")]
        public DateTime? DataDiNascita { get; set; }
    }

    public class LRDReparto
    {
        public int Id { get; set; }
    }

    public class LRDPriorita
    {
        public int Id { get; set; }
    }

    public class LRDLaboratorio
    {
        public int Id { get; set; }
    }

    public class LRDDevice
    {
        public int Id { get; set; }
    }

    public class LRDConnessione
    {
        public int Id { get; set; }

        public int DeviceId { get; set; }
        
        public int StatoConnessione { get; set; }
    }

    public class LRAAlert
    {
        public int Id { get; set; }

        public int DeviceID { get; set; }
        
        public int Visto { get; set; }
        
        public int Tipo { get; set; }
    }
    
    public static class SiNo
    {
        public static int No { get; set; }
        
        public static int Si { get; set; }
    }
    
    public static class TipoAlert
    {
        public static int AlertQC { get; set; }
        
        public static int WarningDevice { get; set; }
    }

    public class DeviceDashboardDTO
    {
        public int DeviceId { get; set; }
        public int StatoLinea { get; set; }
        public int StatoQC { get; set; }
        public int StatoWarning { get; set; }
    }
    
    [Alias("LRARISULTATI")]
    [CompositeIndex("AANALISIID", "DRISULTATOID", "STATO", Unique = false, Name = "IDXLRARISULTATI")]
    public class LRARisultato : DBObject, IHasId<int>
    {
        [PrimaryKey]
        [AutoIncrement]
        [Alias("IDARISULTATO")]
        public int Id { get; set; }

        [Index]
        [Alias("AANALISIID")]
        public int AnalisiId { get; set; }

        [Required]
        [Alias("TIPOVALORE")]
        public int TipoValore { get; set; }

        [Alias("OPERATORERELAZIONALE")]
        public string OperatoreRelazionale { get; set; }

        [Alias("VALORENUMERICO")]
        public decimal? ValoreNumerico { get; set; }

        [Index]
        [Alias("DTESTOCODIFICATOID")]
        public int? TestoCodificatoId { get; set; }

        [Alias("TESTOLIBERO")]
        [StringLength(StringLengthAttribute.MaxText)]
        public string TestoLibero { get; set; }

        [Index]
        [Alias("DRISULTATOID")]
        public int RisultatoId { get; set; }

        [Required]
        [Alias("STATO")]
        public int Stato { get; set; }

        [Alias("INVIAREALIS")]
        public int InviareALIS { get; set; }

        [Alias("RISULTATOPRINCIPALE")]
        public int RisultatoPrincipale { get; set; }

        [Alias("TIPOINSERIMENTO")]
        public int TipoInserimento { get; set; }

        [Index]
        [Alias("DOPERATOREINSERIMENTOID")]
        public int? OperatoreInserimentoId { get; set; }

        [Index]
        [Alias("DDEVICEID")]
        public int? DeviceId { get; set; }

        [Index]
        [Alias("DLABORATORIOESECUTOREID")]
        public int? LaboratorioEsecutoreId { get; set; }

        [Alias("CITRATO")]
        public int Citrato { get; set; }

        [Alias("DATAORARIPETIZIONE")]
        public DateTime? DataOraRipetizione { get; set; }

        [Alias("DATAORAESECUZIONE")]
        public DateTime? DataOraEsecuzione { get; set; }

        [Alias("DATAORARICEZIONE")]
        public DateTime DataOraRicezione { get; set; }

        [Alias("IDENTIFICATIVODEVICE")]
        public string IdentificativoDevice { get; set; }

        [Alias("POSIZIONESUDEVICE")]
        public string PosizioneSuDevice { get; set; }

        [Alias("REAGENTE")]
        public string Reagente { get; set; }

        [Alias("LOTTOREAGENTE")]
        public string LottoReagente { get; set; }

        [Alias("DATASCADENZAREAGENTE")]
        public DateTime? DataScadenzaReagente { get; set; }

        [Alias("CURVADICALIBRAZIONE")]
        public string CurvaDiCalibrazione { get; set; }

        [Index]
        [Alias("DDILUIZIONEID")]
        public int? DiluizioneId { get; set; }

        [Index]
        [Alias("DRANGENORMALITAID")]
        public int? RangeNormalitaId { get; set; }

        [Index]
        [Alias("DRANGECONVALIDAID")]
        public int? RangeConvalidaId { get; set; }

        [Index]
        [Alias("DDELTACHECKSTORICOID")]
        public int? DeltaCheckStoricoId { get; set; }

        [Index]
        [Alias("DDELTACHECKROUTINEID")]
        public int? DeltaCheckRoutineId { get; set; }

        [Index]
        [Alias("DREGOLACONVALIDAID")]
        public int? RegolaConvalidaId { get; set; }

        [Alias("COMMENTO")]
        [StringLength(StringLengthAttribute.MaxText)]
        public string Commento { get; set; }

        [StringLength(250)]
        [Alias("RISULTATORAW")]
        public string RisultatoRaw { get; set; }

        [Index]
        [References(typeof(LRARisultato))]
        [Alias("ADELTARISULTATOSTORICODID")]
        public int? DeltaRisultatoStoricoId { get; set; }

        [Index]
        [References(typeof(LRARisultato))]
        [Alias("ADELTARISULTATOPRECEDENTEID")]
        public int? DeltaRisultatoPrecedenteId { get; set; }
    }
    
    [Alias("LRDPROFILOANALISI")]
    [CompositeIndex("DPROFILOANALISIID", "DANALISIID", Unique = true, Name = "IDXPROFILO")]
    public class LRDProfiloAnalisi : DBObject, IHasId<int>
    {
        [Alias("IDDPROFILOANALISI")]
        [AutoIncrement]
        [PrimaryKey]
        public int Id { get; set; }

        [ApiMember(Description = "Analisi profilo a cui appartiene l'analisi")]
        [Alias("DPROFILOANALISIID")]
        [References(typeof(LRDProfiloAnalisi))]
        public int? ProfiloAnalisiId { get; set; } // dove NULL allora DANALISIID e' l'analisi profilo

        [ApiMember(Description = "Analisi dal dizionario")]
        [Alias("DANALISIID")]
        [References(typeof(LRDAnalisi))]
        public int AnalisiId { get; set; }
    }
    
    [Alias("LRDCONTENITORI")]
    public class LRDContenitore : DBObject, IHasId<int>
    {
        private const int CColore = 7; // lunghezza colore HTML es. #AABBCC
        private const int CPrefisso = 5;

        [Alias("IDDCONTENITORE")]
        [AutoIncrement]
        [PrimaryKey]
        public int Id { get; set; }

        [Alias("CODICE")]
        [Required]
        [Index(Unique = true)]
        public string Codice { get; set; }

        [Required]
        [Alias("DESCRIZIONE")]
        public string Descrizione { get; set; }

        [Alias("DESCRIZIONEESTESA")]
        public string DescrizioneEstesa { get; set; }

        [Alias("ORDINE")]
        [Required]
        public int Ordine { get; set; }

        [Required]
        [Alias("TIPOCONTENITORE")]
        public int TipoContenitore { get; set; }

        [Alias("COLORE")]
        [StringLength(CColore)]
        public string Colore { get; set; }

        [Alias("PREFISSO")]
        [StringLength(CPrefisso)]
        public string Prefisso { get; set; }

        [Alias("PROGRESSIVOBARCODEMIN")]
        [DecimalLength(30, 0)]
        public decimal ProgressivoBarcodeMin { get; set; }

        [Alias("PROGRESSIVOBARCODEMAX")]
        [DecimalLength(30, 0)]
        [Default(int.MaxValue)]
        public decimal ProgressivoBarcodeMax { get; set; }

        [Alias("DMATERIALEID")]
        public int? MaterialeId { get; set; }

        [Alias("DETICHETTAID")]
        public int? EtichettaId { get; set; }

        [Required]
        [Alias("EMATOLOGIA")]
        public int Ematologia { get; set; }

        [Required]
        [Alias("URINE")]
        public int Urine { get; set; }
    }    

    [Alias("LRDANALISI")]
    public class LRDAnalisi : DBObject, IHasId<int>
    {
        [Alias("IDDANALISI")]
        [AutoIncrement]
        [PrimaryKey]
        public int Id { get; set; }

        [Alias("CODICE")]
        [Required]
        [Index(Unique = true)]
        public string Codice { get; set; }

        [Alias("DESCRIZIONE")]
        [Required]
        public string Descrizione { get; set; }

        [Alias("DESCRIZIONEESTESA")]
        public string DescrizioneEstesa { get; set; }

        [Alias("CODICEREGIONALE")]
        public string CodiceRegionale { get; set; }

        [Alias("DCONTENITOREID")]
        public int ContenitoreId { get; set; }

        [Alias("ORDINE")]
        public int Ordine { get; set; }

        [Alias("DMETODOID")]
        public int? MetodoId { get; set; }

        [Alias("DPANNELLOANALISIID")]
        public int? PannelloAnalisiId { get; set; }

        [Alias("DCLASSEANALISIID")]
        public int? ClasseAnalisiId { get; set; }

        [Alias("QCREGISTRAZIONERISULTATI")]
        public int QCRegistrazioneRisultati { get; set; }

        [Alias("QCVERIFICA")]
        public int QCVerifica { get; set; }

        [Alias("QCOREINTERVALLOVERIFICA")]
        public int? QCOreIntervalloVerifica { get; set; }
    }    
}