简体   繁体   中英

Credit Card Expiry Check Linq C#

My application automatically bills subscribed customers using a payment processing vendor. I keep only information on the expiry date of the card and the vendors reference number for auto-billing. Everyday I want to check members whose cards will expire within 30 days. I am running a background process to send email reminders. I am struggling getting Linq to accept my query. The expiry date is stored in the database as a string eg 0319 for March 2019. I am wondering if I have any chance of getting this to work. Please assist if you can. My last resort might be having to format expiry dates currently stored as strings mmyy in database to proper dates.

int mon = DateTime.Now.Month;
int yr = DateTime.Now.Year;
int days = DateTime.DaysInMonth(yr, mon);
int dy = DateTime.Now.Day;
var allCardExpiring = db.DirectDebits.Include(i => i.Customer).Where(a =>a.DdOk && a.Customer.PassOk &&  DateTime.DaysInMonth(Convert.ToInt32(a.DateExpiry.Substring(2, 4)), Convert.ToInt32(a.DateExpiry.Substring(0, 2)))+days-dy < 30).Select(a => a.DirectDebitId).Distinct().ToList();

This is a good example that shows that you should not form the database into the format that operators use to enter their input. If your database would have had the ExpiryDate as a DateTime, you wouldn't have had this problem. Of course with the cost that when operators enter their expiry date you would have to convert it to a DateTime, but (1) that is easier than converting back and (2) What do you more often: query the ExpiryDate or update it?

If you are stuck with this database, then my advice would be to create a query where you split your MonthYear property into aa Month and a Year , using DbFunctions.Left and DbFunctions.Right then convert it in your query to a proper DateTime using DbFunctions.CreateDateTime

If you need this conversion for other functions, consider creating separate IQueryable functions for this, so you can re-use it.

As extension function for your DirectDebit that takes an input sequence of DirectDebits and returns a DateTimeDirectDebit sequence:

public static IQueryable<DateTimeDirectDebit> ToDateTimeDirectDebits(
    this IQueryable<DirectDebit> directDebits)
{
    return directDebits.Select(directDebit => new
    {
        // split ExpiryDate into a Month and a Year
        ExpiryDate = new
        {
            Month = DbFunctions.Left(directDebit.DateExpire, 2),
            Year = DbFunctions.Right(directDebit.DateExpire, 2),
        }
        DirectDebit = directDebit,
    })
    .Select(directDebit => new DateTimeDirectDebit
    {
         // create the ExpiryDate as DateTime
         ExpiryDate = DbFunctions.CreateDateTime(
            directDebit.ExpiryDate.Year,
            directDebit.ExpiryDate.Mnth,
            1,                                // first day of the month
            ...),
         DirectDebit = directDebit.DirectDebit,
    });
}

You also need a function that returns the DateTimeDirectDebits that expire within a certain amount of days. Again as an extension method:

public static IQueryable<DateTimeDirectDebit> WhereExpiresWithinDays(
   this IQueryable<DateTimeDirectDebit> source,
   int nrOfDays)
{
    DateTime now = DateTime.now;
    DateTime limitDate = now.AddDays(nrOfDays);
    return source.Where(directDebit => directDebit.ExpiryDate < limitDate);
}

Similarly you might want a function that returns all directDebits that expire next Month use DbFunctions.DiffMonths for this.

Usage:

using (var dbContext = new ...)
{
    var directDebitsThatExpireNextMonth = dbContext.DirectDebits
        .ToDateTimeDirectDebits
        .WhereExpiresWithinDays(30)
        .Select(...);
}

The nice thing is, that by using these LINQ-like extension methods, you can hide how your database is structured, especially the parts that you are not happy about. This way, your code does not have to be restructures so much if your database changes internally, especially those functions that don't use these changes.

Of course, for a proper hiding of the database structure, class DateTimeDirectDebits should not expose property DirectDebits, but only the properties you want to show to the outside world.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM