Filter all tables on Context Level - entity-framework

I am using EF code first approch. Here is my context file.
public class MyContext : DbContext
{
public DbSet<Contact> Contacts { get; set; }
public DbSet<Contact_phone> Contact_phones{ get; set; }
}
I want to add filter on bases of date on my context file, so that when i get data for any table i get for that specific date range only.
Please suggest.

Disclaimer: I'm the owner of the project Entity Framework Plus
The library has a Query Filter which does exactly this scenario.
Under the hood, it uses interceptor (for EF6) as Steve Grene suggested.
Wiki: EF+ Query Filter
Filter Global
startDate = new DateTime(2015, 1, 1);
QueryFilterManager.Filter<Contacts>(q => q.Where(x => x.CreatedDate > startDate));
// SELECT * FROM Contacts WHERE CreatedDate > '2015-01-01'
var context = ctx.Contacts.ToList();
Filter By Instance
startDate = new DateTime(2015, 1, 1);
var ctx = new MyContext();
ctx.Filter<Contacts>(q => q.Where(x => x.CreatedDate > startDate));
// SELECT * FROM Contacts WHERE CreatedDate > '2015-01-01'
var context = ctx.Contacts.ToList();

Related

EF 3.1/6.0 throw exception `Argument types do not match`, when select field as AsQueryable

I try upgrade project from netcore 2.2 to netcore 3.1, after upgrade to 6.0.7. On netcore 2.2 code work.
If i select only data (without AsQueryable(), only id ) code work on 3.1. If try get any of fields, which defined as IQueryable<...> - always throw exception.
EF 6 return
Message=The query contains a projection 's => s.Emails
.Select(e => new Email{ Value = e.Value }
)
.AsQueryable()' of type 'IQueryable'. Collections in the final projection must be an 'IEnumerable' type such as
'List'. Consider using 'ToList' or some other mechanism to convert
the 'IQueryable' or 'IOrderedEnumerable' into an
'IEnumerable'.
How it work in netcore 2.2:
function return general Queryable object
for table request called this function, and apply same filters, extended query - such by email - add where <condition> for email
if add where for emails - ef generate sql with same condition for filter by email
if not added where - nothing happened
Simplified code sample:
IQueryable<UserView> users = query
.AsNoTracking()
.Select(s => new UserView()
{
UserId = s.Id,
AccountId = null,
Emails = s.Emails.Select(e => new Email()
{
Value = e.Value
}).AsQueryable()
};
var tmp = users.Take(2).Skip(20).ToList();
class definition
public class UserView
{
public int UserId { get; set; }
public int? AccountId { get; set; }
public IQueryable<Email> Emails { get; internal set; }
}

Clear DataGridView datasource linked to Entity Framework

I'm new to Entity Framework, I have a DataGridView connected to Entity Framework as it shown below
dgvDebit.DataSource = (from daily in accountingEntities.DailyAccounts
join voucherdetails in accountingEntities.VoucherDetails on daily.DailyId equals voucherdetails.DailyId
where voucherdetails.VoucherId == keyvalue
group voucherdetails by daily.DailyName into dgroup
select new
{
DailyName = dgroup.Key,
SumOfDebit = dgroup.Sum(s => s.Debit)
}).ToList();
My question is: I want to clear DataGridView datasource but every thing I did has failed - please any help here?
OK, so you want to bind to an empty list of the type that you have.
Step 1: define a .NET type for your query result return type:
public class ResultDTO
{
public string DailyName { get; set; }
public decimal SumOfDebit { get; set; }
}
Step 2: change your "normal" query to:
dgvDebit.DataSource = (from daily in accountingEntities.DailyAccounts
join voucherdetails in accountingEntities.VoucherDetails on daily.DailyId equals voucherdetails.DailyId
where voucherdetails.VoucherId == keyvalue
group voucherdetails by daily.DailyName into dgroup
select new ResultDTO
{
DailyName = dgroup.Key,
SumOfDebit = dgroup.Sum(s => s.Debit)
}).ToList();
Step 3: if you want to "clear" the DataGridView, but retain the columns, you can now use:
dgvDebit.DataSource = new List<ResultDTO>();

EF core paging. Select total count in same query

I have paging and i want to select count in the same query using simple sql (EF7):
var selectSql = " SELECT TotalCount = COUNT(*) OVER(), E.* FROM [table] E ...";
var rows = context.Set<EventTable>().FromSql<EventTable>(selectSql, parameters.Select(p => p.Value).ToArray()).ToArray();
This select works, but i don't have TotalCount property in my EventTable class, because i don't want that property in database.
I try get TotalCount property from entity tracker:
var row = rows.First();
var entity = context.Entry(row);
var totalCount = entity.Property<int>("TotalCount").CurrentValue;
But then i get error:
The property 'TotalCount' on entity type 'EventTable' could not be found. Ensure that the property exists and has been included in the model.
Then i try to add property in model like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EventTable>(b => b.Property<int>("TotalCount"));
}
It works fine when i want to select, but it throws an exception on insert, because column in database not exist.
And EF will add that column on migration. But i notice, that if before migration generation i add line b.Property("TotalCount"); into ModelSnapshot class it will avoid to add property on migration. But problem on insert still exist.
I try to create another class:
[NotMapped]
public class EventSearchTable : EventTable
{
[Column("total_count")]
[Required]
public int TotalCount { get; set; }
}
and then do this:
var rows = context.Set<EventSearchTable>().FromSql<EventSearchTable>(..);
It works on EF6, but not on EF7, i got error: Value cannot be null.
Parameter name: entityType Because no entity in my DbContext. If i will add EventSearchTable class on my DbContext then it will expect columns like discriminator and etc and will create table in migrations.
Any ideas how to get property TotalCount ?
The following query will get the count and page results in one trip to the database
var query = context.Set<EventTable>();
var page = query.OrderBy(e => e.Id)
.Select(e => e)
.Skip(100).Take(100)
.GroupBy(e => new { Total = query.Count() })
.FirstOrDefault();
if (page != null)
{
int total = page.Key.Total;
List<EventTable> events = page.Select(e => e).ToList();
}

How do I add a reference to another existing entity using code-first framework without first pulling the existing entity from the database

I'm trying to attach an existing product to an auction, but am unable to do so without first pulling the product from the database.
This code works, but how would I go about just providing the productid and then saving the auction
var product = new Product()
{
//Known existing product id
ProductId = 1
};
var auction = new Auction
{
BuyItNowPrice = 10.
Product = product,
...
...
};
using (var db = new DataContext())
{
var product = db.Products.Find(auction.Product.ProductId);
auction.Product = product;
db.Auctions.Add(auction);
db.SaveChanges();
}
Include the scalar property ProductId in the Auction class
public class Auction
{
public int Id {get;set;}
public int ProductId {get;set;}
public Product Product {get;set;}
//other proerties
}
Then
auction.ProductId = 1;
db.Auctions.Add(auction);
db.SaveChanges();

How to ask the database server for current datetime using entity framework?

I have an entity with a ModifiedDateTime property which I want to be updated with the current datetime from the database instead of the "application" server executing the application.
Every time I want to update or add a person to my datebase on SQL Server 2008 I want to fill ModifiedDateTime filed. It's not like I can change update query as with data adapter command when I work with dataset and to define for my ModifiedDateTime filed to be GetDate(). I created stored function to return me a value of GetDate() method, but I have a problem to import procedure which returns values as int, string or no value at all, already just entity values as Person for example in my case. Why is that?
Anyway, it would be of great help if you can help me to retrieve the current DateTime from the database server.
Is there a reason you just can't push it down to your database? If you include DateTime.Now in your entity query, it will push it down (getdate) to the database.
Example linq to entities
var dQuery = dbContext.CreateQuery<DateTime>("CurrentDateTime() ");
DateTime dbDate = dQuery.AsEnumerable().First();
SQL Generated ..
SELECT GetDate() AS [C1] FROM ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1]
Might be a better way to do it ?
This is an update of #Nix response to EF4:
var dateQuery = dbContext.Database.SqlQuery<DateTime>("SELECT getdate()");
DateTime serverDate = dateQuery.AsEnumerable().First();
An update for .net core 2.0
var dual = databaseContext
.Set<Dual>()
.FromSql("SELECT -1 AS Id, GETDATE() AS DateTime")
.First();
The fake entity
public class Dual
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
}
In VS 2008, if you add a function template to return a scalar, it does not add the code to make it easy to use. You need to access the function template directly -- I use the partial class to build the needed methods for ease of use. They fixed this in VS2010.
public DateTime GetDateTime()
{
var returnValue = new DateTime();
using (var connection = new EntityConnection(Connection.ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "myStoredProc";
command.CommandType = CommandType.StoredProcedure;
try
{
returnValue = Convert.ToDateTime(command.ExecuteScalar());
}
finally
{
connection.Close();
}
}
}
return returnValue;
}
More information:
Function Imports in Entity Model with a non-Entity Return Type
EF 3
var dual = await db
.Set<Dual>()
.FromSqlRaw(#"
SELECT
CURRENT_TRANSACTION_ID() as Id,
SYSDATETIMEOFFSET() AS DateTime
")
.FirstAsync();
DateTimeOffset serverTime = dual.DateTime;
public class Dual
{
public long Id { get; set; }
public DateTimeOffset DateTime { get; set; }
}
modelBuilder.Entity<Dual>(entity =>
{
entity.HasNoKey();
entity.ToView(nameof(Dual));
});