5

The following linq

var subjectMarks = (from DataRow row in objDatatable.Rows
                    select Convert.ToDecimal(row["EXM_MARKS"])).Sum();

throws an exception since some row["EXM_MARKS"] has non numeric values like AB etc. How can I get the sum of only numeric ones out of them?

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
Kuntady Nithesh
  • 11,371
  • 20
  • 63
  • 86

7 Answers7

9

Add where clause that filters out the records that cannot be parsed as decimals. Try:

decimal dummy;

var subjectMarks = (from DataRow row in objDatatable.Rows
                     where decimal.TryParse(row["EXM_MARKS"], out dummy)
                     select Convert.ToDecimal(row["EXM_MARKS"])).Sum();
Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
5

You could create an extension method SafeConvertToDecimal and use this in your LINQ query:

var subjectMarks = (from DataRow row in objDatatable.Rows
                    select row["EXM_MARKS"].SafeConvertToDecimal()).Sum();

This extension method would look like this:

public static decimal SafeConvertToDecimal(this object obj)
{
    decimal result;
    if(!decimal.TryParse(obj.ToString(), out result))
        result = 0;

    return result;
}

This approach has the advantage that it looks clean and you aren't converting each object twice as do all other answers.  

Khalil
  • 1,047
  • 4
  • 17
  • 34
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
2

For linq to sql queries you can use built-in SqlFunctions.IsNumeric

Source: SqlFunctions.IsNumeric

irfandar
  • 1,690
  • 1
  • 23
  • 24
1

For LINQ to SQL queries with Entity Framework Core, ISNUMERIC function is part of EF Core 6.0 under EF.Functions

Before version 6.0, you can create a user-defined function mapping !

User-defined function mapping : Apart from mappings provided by EF Core providers, users can also define custom mapping. A user-defined mapping extends the query translation according to the user needs. This functionality is useful when there are user-defined functions in the database, which the user wants to invoke from their LINQ query for example.

await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();

_ = await ctx.Blogs.Where(b => ctx.IsNumeric(b.Name)).ToListAsync();

public class BlogContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    static ILoggerFactory ContextLoggerFactory
        => LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(@"Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0")
            .EnableSensitiveDataLogging()
            .UseLoggerFactory(ContextLoggerFactory);

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDbFunction(IsNumericMethodInfo)
            .HasName("ISNUMERIC")
            .IsBuiltIn();
    }

    private static readonly MethodInfo IsNumericMethodInfo = typeof(BlogContext)
        .GetRuntimeMethod(nameof(IsNumeric), new[] { typeof(string) });

    public bool IsNumeric(string s) => throw new NotSupportedException();
}

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
}
A. Morel
  • 9,210
  • 4
  • 56
  • 45
  • Please avoid the phrase "LINQ to SQL" in an Entity Framework context. It's quite a different thing. – Gert Arnold Jul 29 '22 at 17:54
  • It's worth noting that the built-in `ISNUMERIC` will return true for some non-numeric characters, e.g., "+20", "-30", "$2.00". But for expressions like "20+" it will return false, so character positioning matters. Bottom line: If you're looking strictly to exclude all non-numeric characters, you'll need to look elsewhere. – Tawab Wakil Aug 03 '23 at 21:49
1

use

Decimal Z;

var subjectMarks = (from DataRow row in objDatatable.Rows
                     where Decimal.TryParse (row["EXM_MARKS"], out Z)
                     select Convert.ToDecimal(row["EXM_MARKS"])).Sum();
VdesmedT
  • 9,037
  • 3
  • 34
  • 50
Yahia
  • 69,653
  • 9
  • 115
  • 144
1

You can make some extensions utility class like this for elegant solution:

public static class TypeExtensions
{
    public static bool IsValidDecimal(this string s)
    {
        decimal result;
        return Decimal.TryParse(s, out result);
    }
}

and use it in this way:

var subjectMarks = (from DataRow row in objDatatable.Rows
                     where row["EXM_MARKS"].IsValidDecimal()
                     select Convert.ToDecimal(row["EXM_MARKS"])).Sum();

Hope this helps.

Łukasz Wiatrak
  • 2,747
  • 3
  • 22
  • 38
0
var subjectMarks = objDatatable.Rows.Where(row => row["EXM_MARKS"].ToString().All(char.isDigit))

part of solution is getted in: here

Dave
  • 7,028
  • 11
  • 35
  • 58