Out of the range of DateTime (year must be between 1 and 9999) with Entity Framework Core and PostgreSql - c#

I have the following values in my PostreSql database table on a table column with the data type of timestamp(0):
2023-02-17 19:36:58.000,
2023-02-17 19:46:53.000,
2023-02-17 19:53:45.000
And when I try to run a select query from Entity Framework Core, I get the following error message
Out of the range of DateTime (year must be between 1 and 9999)
This is the code
var sessionStatus = await _unitOfWork.SessionStatusRepository.GetAsync(filter: i => i.SessionId == sessionId);
This is the repository method below:
public async Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
IQueryable<T> query = _dbset;
if (filter != null)
{
query = query.Where(filter);
}
if (includeProperties != null)
{
foreach (var property in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(property);
}
}
if (orderBy != null)
{
return await orderBy(query).ToListAsync();
}
else
{
return await query.ToListAsync();
}
}
And the datetime properties of the entity class as I defined them are as follows:
public class Entityname
{
...
public DateTime TimeStarted { get; set; }
public DateTime LastUpdated { get; set; }
}
Please how can I resolve this?
Thank you

try to convert timestamp values from the database to DateTimeOffset. it represents wide range value that DataTime
use DateTimeOffset.ParseExact("Your date time value".ToString("yyyy-MM-dd HH:mm:ss.fff"), "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)

Related

C# Linq to SQL Query between 2 Dates nos getting results

I'm building a complex search query using Textboxes, Comboboxes and DateTimePicker.
For the Textbox and Combobox, the queries are working fine, but when add a datetimepicker for query between 2 dates, I'm getting nothing...
Using EF6 with LINQ...
So, my class to store data:
public class Projetos
{
public int ID { get; set; }
public string Conc { get; set; } //Combobox
public string Ent { get; set; } //Combobox
public string Def { get; set; } //Textbox
public DateTime DataR { get; set; }
}
The first query and return results:
public IEnumerable<Proj> LoadProj()
{
var ctx = new JEntities();
var query = (from p in ctx.tblProjs.AsQueryable()
join c in ctx.tblConcs on p.ConcID equals c.ConcID
join e in ctx.tblEnts on p.EntID equals e.EntID
select new Proj
{
ID = p.ProjID,
Conc = c.NameConc,
Ent = e.NameEnt,
Def = p.DefP,
DataR = p.DataR
});
// The combination of these 3 controls works fine!
if (TxtDefP.TextLength > 0)
{
query = query.Where(s => s.DefP.Contains(TxtDefP.Text));
}
if(CmbCon.SelectedValue != null)
{
string SelectedValue = CmbConc.GetItemText(CmbConc.SelectedItem);
query = query.Where(s => s.Conc == SelectedValue);
}
if(CmbEnt.SelectedValue != null)
{
string SelectedValue = CmbEnt.GetItemText(CmbEnt.SelectedItem);
query = query.Where(s => s.Ent == SelectedValue);
}
//When filtering between these 2 dates, I get no results
if (DataRFrom.Checked && DataRTo.Checked)
{
DateTime begin = DataRFrom.Value.Date;
DateTime end = DataRTo.Value.Date;
query = query.Where(s => s.DataR > begin && s.DataR < end);
}
return query.ToList();
}
In the SQL, I have dates like this... Perhaps the Date format in SQL are messing up all this???
My questions is, why can't I get any results between 2018-06-01 and 2018-06-06 since records with this date range are in Database?
Thanks.
Date property is missing:
query = query.Where(s => s.DataR.Date > begin && s.DataR.Date < end);

Always getting null when trying to call entity using includeProperties

I have a simple get like this:
var tc = _pService.Listar(includeProperties: "Estatus,CatalogosRegistro");
if (tc != null)
{
List<VehiculoGetViewModel> tiposcargas = new List<VehiculoGetViewModel>();
foreach (var item in tc)
{
var carga = new VehiculoGetViewModel()
{
ID = item.ID,
Nombre = item.Nombre,
NombreEstatus = item.Estatus.Nombre,
NombreContenedor = item.CatalogosRegistro.Nombre
};
tiposcargas.Add(carga);
}
}
As you can see I have includeProperties where I use Estatus and CatalogoRegistro tables.
So when I call NombreEstatus = item.Estatus.Nombre, item.Estatus.Nombre get value correctly but item.CatalogosRegistro always come null
View Model:
public class VehiculoGetViewModel
{
public Int64 ID { get; set; }
public string Nombre { get; set; }
public string NombreEstatus { get; set; }
public Estatus Estatus { get; set; }
public string NombreContenedor { get; set; }
public CatalogoRegistro CatalogosRegistro { get; set; }
}
Model
[Table("TiposVehiculo", Schema="adm")]
public class TipoVehiculo: Entidad<Int32>
{
[StringLength(255)]
public string Nombre { get; set; }
[StringLength(255)]
public int EstatusID { get; set; }
public Estatus Estatus { get; set; }
public CatalogoRegistro CatalogosRegistro { get; set; }
}
Listar implementation:
public virtual IEnumerable<T> Listar(
Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
string includeProperties = "")
{
IQueryable<T> query = _dbset;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).AsEnumerable<T>();
}
else
{
return query.AsEnumerable<T>();
}
}
Strange thing is I don´t have any problems using Estatus and I use same structure to call CatalogoRegistro but it always come null, can some one know what is wrong there? Regards
Update:
After checing query of var tc = _pService.Listar it just throwing all values of inner join with CatalogosRegistros
And that is because I don´t have CatalogosRegistros_ID I just have an TipoContenedorID column. Why EF change name of my ID?
So if I change to TipoContenedorID I get correct values:
Since you don't pass a filter or order by to Listar you don't really even need it.
var tiposcargas = _pService.Select(item => new VehiculoGetViewModel()
{
ID = item.ID,
Nombre = item.Nombre,
NombreEstatus = item.Estatus.Nombre,
NombreContenedor = item.CatalogosRegistro.Nombre
}).ToList();
This way if Estatus or CatalogosRegistro are null because there isn't a matching row in those tables it will just give you null for the Nombre. You may have to use ?? if NombreEstatus and NomberContenedor are not nullable.
Personally I'd drop using the Include and AsEnumerable and and just return the resulting IQueryable and let the caller deal with Includes or just using navigation properties in their select.
public virtual IQueryable<T> Listar(
Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,)
{
IQueryable<T> query = _dbset;
if (filter != null)
{
query = query.Where(filter);
}
if (orderBy != null)
{
return orderBy(query);
}
return query;
}

Send lambda expression from client to server

I have a method that helps to dynamically build a query on a client:
public virtual IList<TEntity> Fill(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
includeProperties = includeProperties ?? "";
var qctx = new TQueryContext
{
QueryType = filter == null ? CommonQueryType.FillAll : CommonQueryType.FillWhere,
Filter = filter,
OrderBy = orderBy
};
qctx.Includes.AddRange(includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
_detachedServerRepo.Read(qctx);
return qctx.Entities;
}
I want to send qctx to a server repo which might be on another machine. Since a TQueryContext will be typed from QueryContextBase defined in part as below I can't serialize it.
public class QueryContextBase<TEntity, TKey>
where TEntity : StateTrackedObject
where TKey : IEquatable<TKey>
{
public TKey ID { get; set; }
public string Alf { get; set; }
public List<TEntity> Entities { get; set; }
public List<string> Includes { get; set; }
public Expression<Func<TEntity, bool>> Filter { get; set; }
public Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> OrderBy { get; set; }
}
How can I create similar properties to Filter and OrderBy so I can serialize them and then build up the query in the server repo as below:
protected override void FillWhere(TQueryContext qctx)
{
qctx.Entities.AddRange(this.Fill(qctx.Filter, qctx.OrderBy,
qctx.GetIncludesAsString()));
}
protected override void FillAll(TQueryContext qctx)
{
qctx.Entities.AddRange(this.Fill(null, qctx.OrderBy, qctx.GetIncludesAsString()));
}
public virtual IEnumerable<TEntity> Fill(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
includeProperties = includeProperties ?? "";
try
{
IQueryable<TEntity> querySet = DbSet;
if (filter != null)
{
querySet = querySet.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
querySet = querySet.Include(includeProperty.Trim());
}
return (orderBy == null) ? querySet.ToList() : orderBy(querySet).ToList();
}
catch (Exception ex)
{
return ex.ThrowDalException<IEnumerable<TEntity>>(OperationType.Read, ex.Message, ex);
}
}
You're right not to want to reinvent the wheel. Check out Serialize.Linq.
You could solve your problem with this library as below:
In your client repo:
public virtual IList<TEntity> Fill(Expression<Func<TEntity, bool>> filter = null,
Expression<Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>>> orderBy = null,
string includeProperties = "") {
includeProperties = includeProperties ?? "";
try
{
var qctx = new TQueryContext
{
QueryType = filter == null ? CommonQueryType.FillAll : CommonQueryType.FillWhere,
FilterNode = filter == null ? null : filter.ToExpressionNode(),
OrderByNode = orderBy == null ? null : orderBy.ToExpressionNode()
};
And then in your QueryContext just add the extra property and convert:
public ExpressionNode FilterNode { get; set; }
public Expression<Func<TEntity, bool>> Filter
{
get {
return FilterNode == null ? null : FilterNode.ToBooleanExpression<TEntity>();
}
}
public ExpressionNode OrderByNode { get; set; }
public Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>> OrderBy
{
get {
return OrderByNode == null ? null : OrderByNode.ToExpression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>();
}
}
It is not possible to serialize a method... any method (lambda, delegate, ...), thus it is not possible to send a method from client to server.
Best you can do is to send a filter to your service, construct the query there and return the result to the client. That is the usual way.
So in your case instead of passing a Func which filters the data pass the values which the filter uses.
To elaborate that, consider this example of server-side method:
DataType[] GetData(Filter filter, Ordering ordering)
{
var data = GetDataQuerySomeHow(); //for example in EF Context.Table
//filter data according to the filter
if (!string.IsNullOrEmpty(filter.FulltextProperty))
{
data = data.Where(a => a.StringProperty.Contains(filter.FulltextProperty));
}
//do similar thing for ordering
return data.ToArray();
}
Filter and ordering:
public class Filter
{
public string FulltextProperty { get; set; }
//some other filtering properties
}
public class Ordering
{
public string ColumnName { get; set; }
public bool Ascending { get; set; }
}
Client
Filter filter = new Filter()
{
//fill-in whatever you need
};
Ordering ordering = new Ordering(); //also fill in
var data = GetData(filter, ordering);
//display data somewhere

how to convert list object to list string( getting error Unable to cast object of type)

Hi Friends i have a list of objects private static List<Transaction> transactions;
i am querying through the list to filter the data with some criteria. but i am not able to return the list string. i am getting the error
Unable to cast object of type
<>f__AnonymousType1`6[System.Int32,System.String,System.String,System.String,System.String,System.String]
to type 'System.String'.
my plan is to make the datagridview source this list like dataGridView2.DataSource = BasicClass.banksearch("ABC");
public static List<string> banksearch(string bankname, string sdate = null, string edate = null, string condition = null)
{
List<string> returnstr = new List<string>();
if (sdate == null && edate == null)//only bank
{
returnstr = transactions
.Where(t => t.BankName == bankname)
.Select(t => new
{
TransactionID = t.TransactionID,
BankName = t.BankName,
TemplateModel = t.TemplateModel,
Date = t.Date.ToString(),
PayeeName = t.PayeeName,
Amount = t.Amount.ToString()
}).Cast<String>().ToList();
}
return returnstr;
}
my class file is
class Transaction
{
public int TransactionID { get; set; }
public string BankName { get; set; }
public string TemplateModel { get; set; }
public DateTime Date { get; set; }
public string PayeeName { get; set; }
public decimal Amount { get; set; }
}
Please give me idea to get the result
There is no need to project the entire collection onto an Anonymous Object.
All you're actually doing is filtering by bankname:
public static List<Transaction> BankSearch(string bankname, string sdate = null, string edate = null, string condition = null)
{
List<Transaction> filteredTransactions = new List<Transaction>();
if (sdate == null && edate == null)
{
filteredTransactions = transactions.Where(t => t.BankName == bankname).ToList();
}
return filteredTransactions;
}
You don't need to convert to a string in order to use this result as a datasource (although if you actually need a string I can show you how to create a formatted string instead of an anonymous class object). You likely need something like this:
public static List<Transaction> banksearch(string bankname, string sdate = null, string edate = null, string condition = null)
{
if (sdate == null && edate == null)//only bank
{
return transactions // type: List<Transaction>
.Where(t => t.BankName == bankname)
.ToList();
} else {
return new List<Transaction>();
}
}

how to use Attribute.IsDefined in entity framework 5?

I am using the entity framework to create an audit trail. Rather than audit every property, I thought I would create a custom attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DoNotAudit : Attribute
{
}
Then I would apply this to my model
[Table("AuditZone")]
public class AuditZone
{
public AuditZone()
{
AuditZoneUploadedCOESDetails = new List<UploadedCOESDetails>();
AuditZonePostcode = new List<Postcodes>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public bool Valid { get; set; }
public DateTime CreatedDate { get; set; }
public int? CreatedBy { get; set; }
[DoNotAudit]
public DateTime? ModifiedDate { get; set; }
public int? ModifiedBy { get; set; }
public virtual UserProfile CreatedByUser { get; set; }
public virtual UserProfile ModifiedByUser { get; set; }
public virtual ICollection<UploadedCOESDetails> AuditZoneUploadedCOESDetails { get; set; }
public virtual ICollection<Postcodes> AuditZonePostcode { get; set; }
}
Then in my code for the audit trail
// This is overridden to prevent someone from calling SaveChanges without specifying the user making the change
public override int SaveChanges()
{
throw new InvalidOperationException("User ID must be provided");
}
public int SaveChanges(int userId)
{
// Get all Added/Deleted/Modified entities (not Unmodified or Detached)
foreach (var ent in this.ChangeTracker.Entries().Where(p => p.State == System.Data.EntityState.Added || p.State == System.Data.EntityState.Deleted || p.State == System.Data.EntityState.Modified))
{
// For each changed record, get the audit record entries and add them
foreach (AuditLog x in GetAuditRecordsForChange(ent, userId))
{
this.AuditLogs.Add(x);
}
}
// Call the original SaveChanges(), which will save both the changes made and the audit records
return base.SaveChanges();
}
private List<AuditLog> GetAuditRecordsForChange(DbEntityEntry dbEntry, int userId)
{
List<AuditLog> result = new List<AuditLog>();
DateTime changeTime = DateTime.UtcNow;
// Get the Table() attribute, if one exists
//TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), true).SingleOrDefault() as TableAttribute;
// Get table name (if it has a Table attribute, use that, otherwise get the pluralized name)
string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
// Get primary key value (If you have more than one key column, this will need to be adjusted)
var keyNames = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).ToList();
string keyName = keyNames[0].Name;
var test = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Count() > 0).ToList();
// //dbEntry.Entity.GetType().GetProperties().Single(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0).Name;
if (dbEntry.State == System.Data.EntityState.Added)
{
// For Inserts, just add the whole record
// If the entity implements IDescribableEntity, use the description from Describe(), otherwise use ToString()
foreach (string propertyName in dbEntry.CurrentValues.PropertyNames)
{
result.Add(new AuditLog()
{
AuditLogId = Guid.NewGuid(),
UserId = userId,
EventDateUTC = changeTime,
EventType = "A", // Added
TableName = tableName,
RecordId = dbEntry.CurrentValues.GetValue<object>(keyName).ToString(),
ColumnName = propertyName,
NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
}
);
}
}
else if (dbEntry.State == System.Data.EntityState.Deleted)
{
// Same with deletes, do the whole record, and use either the description from Describe() or ToString()
result.Add(new AuditLog()
{
AuditLogId = Guid.NewGuid(),
UserId = userId,
EventDateUTC = changeTime,
EventType = "D", // Deleted
TableName = tableName,
RecordId = dbEntry.OriginalValues.GetValue<object>(keyName).ToString(),
ColumnName = "*ALL"//,
// NewValue = (dbEntry.OriginalValues.ToObject() is IDescribableEntity) ? (dbEntry.OriginalValues.ToObject() as IDescribableEntity).Describe() : dbEntry.OriginalValues.ToObject().ToString()
}
);
}
else if (dbEntry.State == System.Data.EntityState.Modified)
{
foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
{
var doNotAUditDefined = dbEntry.Property(propertyName).GetType().GetCustomAttributes(typeof(DoNotAudit), false);
// var test1 = dbEntry.Property(propertyName).GetType().Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Count() > 0).ToList();
// var test = dbEntry.Entity.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Count() > 0).ToList();
// For updates, we only want to capture the columns that actually changed
if (!object.Equals(dbEntry.OriginalValues.GetValue<object>(propertyName), dbEntry.CurrentValues.GetValue<object>(propertyName)))
{
result.Add(new AuditLog()
{
AuditLogId = Guid.NewGuid(),
UserId = userId,
EventDateUTC = changeTime,
EventType = "M", // Modified
TableName = tableName,
RecordId = dbEntry.OriginalValues.GetValue<object>(keyName).ToString(),
ColumnName = propertyName,
OriginalValue = dbEntry.OriginalValues.GetValue<object>(propertyName) == null ? null : dbEntry.OriginalValues.GetValue<object>(propertyName).ToString(),
NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
}
);
}
}
}
// Otherwise, don't do anything, we don't care about Unchanged or Detached entities
return result;
}
In the modified section I have the following line of code
var doNotAUditDefined = dbEntry.Property(propertyName).GetType().GetCustomAttributes(typeof(DoNotAudit), false);
WHen I step through the code, even for the modifiedDate property this is shown as empty. How can that be? any help is appreciated
Thanks
What you get with the following code:
dbEntry.Property(propertyName).GetType()
is the type of the modified property, like DateTime? in the case of ModifiedType. So there is no attribute defined on the DateTime? class. (As the attribute is defined in your AuditZone class)
What I would do is to save the list of properties that should not be audited before entering into the modified part of your audit code (at least before looping the list of modified properties). Then as looping through the modified properties, check if the property name is in the list of properties excluded from audit. Something like this:
var auditExcludedProps = dbEntry.Entity.GetType()
.GetProperties()
.Where(p => p.GetCustomAttributes(typeof(DoNotAudit), false).Any())
.Select(p => p.Name)
.ToList();
foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
{
var doNotAUditDefined = auditExcludedProps.Contains(propertyName);
...
}
You may want to double check that dbEntry.Entity.GetType() returns your class AuditZone and the list auditExcludedProps contains the ModifiedDate property.
Hope it helps!

Categories