Skip to content

Commit 648281e

Browse files
committed
Minor performance optimizations
1 parent ed48f2d commit 648281e

33 files changed

Lines changed: 126 additions & 107 deletions

src/Libraries/SmartStore.Core/BaseEntity.cs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,15 @@ namespace SmartStore.Core
1313
[DataContract]
1414
public abstract partial class BaseEntity
1515
{
16-
/// <summary>
16+
private int? _cachedHashcode;
17+
18+
/// <summary>
1719
/// Gets or sets the entity identifier
1820
/// </summary>
19-
[DataMember, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
21+
[DataMember]
22+
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
2023
public int Id { get; set; }
2124

22-
public override bool Equals(object obj)
23-
{
24-
return Equals(obj as BaseEntity);
25-
}
26-
27-
private static bool IsTransient(BaseEntity obj)
28-
{
29-
return obj != null && Equals(obj.Id, default(int));
30-
}
31-
3225
public Type GetUnproxiedType()
3326
{
3427
var t = GetType();
@@ -40,32 +33,61 @@ public Type GetUnproxiedType()
4033
return t;
4134
}
4235

43-
public virtual bool Equals(BaseEntity other)
36+
/// <summary>
37+
/// Transient objects are not associated with an item already in storage. For instance,
38+
/// a Product entity is transient if its Id is 0.
39+
/// </summary>
40+
public virtual bool IsTransient
41+
{
42+
get { return Id == 0; }
43+
}
44+
45+
public override bool Equals(object obj)
46+
{
47+
return Equals(obj as BaseEntity);
48+
}
49+
50+
protected virtual bool Equals(BaseEntity other)
4451
{
4552
if (other == null)
4653
return false;
4754

4855
if (ReferenceEquals(this, other))
4956
return true;
5057

51-
if (!IsTransient(this) &&
52-
!IsTransient(other) &&
53-
Equals(Id, other.Id))
58+
if (HasSameNonDefaultIds(other))
5459
{
5560
var otherType = other.GetUnproxiedType();
56-
var thisType = GetUnproxiedType();
57-
return thisType.IsAssignableFrom(otherType) ||
58-
otherType.IsAssignableFrom(thisType);
61+
var thisType = this.GetUnproxiedType();
62+
return thisType.Equals(otherType);
5963
}
6064

6165
return false;
6266
}
6367

6468
public override int GetHashCode()
6569
{
66-
if (Equals(Id, default(int)))
67-
return base.GetHashCode();
68-
return Id.GetHashCode();
70+
// once hashcode is generated, never change it!
71+
if (_cachedHashcode.HasValue)
72+
return _cachedHashcode.Value;
73+
74+
if (this.IsTransient)
75+
{
76+
_cachedHashcode = base.GetHashCode();
77+
}
78+
else
79+
{
80+
unchecked
81+
{
82+
// It's possible for two objects to return the same hash code based on
83+
// identically valued properties, even if they're of two different types,
84+
// so we include the object's type in the hash calculation
85+
int hashCode = GetUnproxiedType().GetHashCode();
86+
_cachedHashcode = (hashCode * 31) ^ Id.GetHashCode();
87+
}
88+
}
89+
90+
return _cachedHashcode.Value;
6991
}
7092

7193
public static bool operator ==(BaseEntity x, BaseEntity y)
@@ -77,5 +99,10 @@ public override int GetHashCode()
7799
{
78100
return !(x == y);
79101
}
102+
103+
private bool HasSameNonDefaultIds(BaseEntity other)
104+
{
105+
return !this.IsTransient && !other.IsTransient && this.Id == other.Id;
106+
}
80107
}
81108
}

src/Libraries/SmartStore.Core/Domain/Blogs/BlogPost.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public partial class BlogPost : BaseEntity, ISlugSupported, IStoreMappingSupport
9393
/// </summary>
9494
public virtual ICollection<BlogComment> BlogComments
9595
{
96-
get { return _blogComments ?? (_blogComments = new List<BlogComment>()); }
96+
get { return _blogComments ?? (_blogComments = new HashSet<BlogComment>()); }
9797
protected set { _blogComments = value; }
9898
}
9999

src/Libraries/SmartStore.Core/Domain/Catalog/Category.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Runtime.Serialization;
45
using SmartStore.Core.Domain.Discounts;
56
using SmartStore.Core.Domain.Localization;
@@ -14,6 +15,7 @@ namespace SmartStore.Core.Domain.Catalog
1415
/// Represents a category
1516
/// </summary>
1617
[DataContract]
18+
[DebuggerDisplay("{Id}: {Name} (Parent: {ParentCategoryId})")]
1719
public partial class Category : BaseEntity, ISoftDeletable, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported
1820
{
1921
private ICollection<Discount> _appliedDiscounts;
@@ -167,13 +169,8 @@ public partial class Category : BaseEntity, ISoftDeletable, ILocalizedEntity, IS
167169
[DataMember]
168170
public virtual ICollection<Discount> AppliedDiscounts
169171
{
170-
get { return _appliedDiscounts ?? (_appliedDiscounts = new List<Discount>()); }
172+
get { return _appliedDiscounts ?? (_appliedDiscounts = new HashSet<Discount>()); }
171173
protected set { _appliedDiscounts = value; }
172174
}
173-
174-
public override string ToString()
175-
{
176-
return string.Format( "{0}: {1} (Parent: {2})", this.Id, this.Name, this.ParentCategoryId);
177-
}
178175
}
179176
}

src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ public RecurringProductCyclePeriod RecurringCyclePeriod
914914
[DataMember]
915915
public virtual ICollection<ProductCategory> ProductCategories
916916
{
917-
get { return _productCategories ?? (_productCategories = new List<ProductCategory>()); }
917+
get { return _productCategories ?? (_productCategories = new HashSet<ProductCategory>()); }
918918
protected set { _productCategories = value; }
919919
}
920920

@@ -924,7 +924,7 @@ public virtual ICollection<ProductCategory> ProductCategories
924924
[DataMember]
925925
public virtual ICollection<ProductManufacturer> ProductManufacturers
926926
{
927-
get { return _productManufacturers ?? (_productManufacturers = new List<ProductManufacturer>()); }
927+
get { return _productManufacturers ?? (_productManufacturers = new HashSet<ProductManufacturer>()); }
928928
protected set { _productManufacturers = value; }
929929
}
930930

@@ -943,7 +943,7 @@ public virtual ICollection<ProductPicture> ProductPictures
943943
/// </summary>
944944
public virtual ICollection<ProductReview> ProductReviews
945945
{
946-
get { return _productReviews ?? (_productReviews = new List<ProductReview>()); }
946+
get { return _productReviews ?? (_productReviews = new HashSet<ProductReview>()); }
947947
protected set { _productReviews = value; }
948948
}
949949

@@ -953,7 +953,7 @@ public virtual ICollection<ProductReview> ProductReviews
953953
[DataMember]
954954
public virtual ICollection<ProductSpecificationAttribute> ProductSpecificationAttributes
955955
{
956-
get { return _productSpecificationAttributes ?? (_productSpecificationAttributes = new List<ProductSpecificationAttribute>()); }
956+
get { return _productSpecificationAttributes ?? (_productSpecificationAttributes = new HashSet<ProductSpecificationAttribute>()); }
957957
protected set { _productSpecificationAttributes = value; }
958958
}
959959

@@ -963,7 +963,7 @@ public virtual ICollection<ProductSpecificationAttribute> ProductSpecificationAt
963963
[DataMember]
964964
public virtual ICollection<ProductTag> ProductTags
965965
{
966-
get { return _productTags ?? (_productTags = new List<ProductTag>()); }
966+
get { return _productTags ?? (_productTags = new HashSet<ProductTag>()); }
967967
protected set { _productTags = value; }
968968
}
969969

@@ -973,7 +973,7 @@ public virtual ICollection<ProductTag> ProductTags
973973
[DataMember]
974974
public virtual ICollection<ProductVariantAttribute> ProductVariantAttributes
975975
{
976-
get { return _productVariantAttributes ?? (_productVariantAttributes = new List<ProductVariantAttribute>()); }
976+
get { return _productVariantAttributes ?? (_productVariantAttributes = new HashSet<ProductVariantAttribute>()); }
977977
protected set { _productVariantAttributes = value; }
978978
}
979979

@@ -993,7 +993,7 @@ public virtual ICollection<ProductVariantAttributeCombination> ProductVariantAtt
993993
[DataMember]
994994
public virtual ICollection<TierPrice> TierPrices
995995
{
996-
get { return _tierPrices ?? (_tierPrices = new List<TierPrice>()); }
996+
get { return _tierPrices ?? (_tierPrices = new HashSet<TierPrice>()); }
997997
protected set { _tierPrices = value; }
998998
}
999999

@@ -1003,7 +1003,7 @@ public virtual ICollection<TierPrice> TierPrices
10031003
[DataMember]
10041004
public virtual ICollection<Discount> AppliedDiscounts
10051005
{
1006-
get { return _appliedDiscounts ?? (_appliedDiscounts = new List<Discount>()); }
1006+
get { return _appliedDiscounts ?? (_appliedDiscounts = new HashSet<Discount>()); }
10071007
protected set { _appliedDiscounts = value; }
10081008
}
10091009

@@ -1013,7 +1013,7 @@ public virtual ICollection<Discount> AppliedDiscounts
10131013
[DataMember]
10141014
public virtual ICollection<ProductBundleItem> ProductBundleItems
10151015
{
1016-
get { return _productBundleItems ?? (_productBundleItems = new List<ProductBundleItem>()); }
1016+
get { return _productBundleItems ?? (_productBundleItems = new HashSet<ProductBundleItem>()); }
10171017
protected set { _productBundleItems = value; }
10181018
}
10191019
}

src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleData.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c
6868
}
6969
return base.ConvertFrom(context, culture, value);
7070
}
71+
7172
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
7273
{
7374
if (destinationType == typeof(string))

src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleItem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public partial class ProductBundleItem : BaseEntity, ILocalizedEntity, ICloneabl
111111
/// </summary>
112112
public virtual ICollection<ProductBundleItemAttributeFilter> AttributeFilters
113113
{
114-
get { return _attributeFilters ?? (_attributeFilters = new List<ProductBundleItemAttributeFilter>()); }
114+
get { return _attributeFilters ?? (_attributeFilters = new HashSet<ProductBundleItemAttributeFilter>()); }
115115
protected set { _attributeFilters = value; }
116116
}
117117

src/Libraries/SmartStore.Core/Domain/Catalog/ProductReview.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public partial class ProductReview : CustomerContent
5050
/// </summary>
5151
public virtual ICollection<ProductReviewHelpfulness> ProductReviewHelpfulnessEntries
5252
{
53-
get { return _productReviewHelpfulnessEntries ?? (_productReviewHelpfulnessEntries = new List<ProductReviewHelpfulness>()); }
53+
get { return _productReviewHelpfulnessEntries ?? (_productReviewHelpfulnessEntries = new HashSet<ProductReviewHelpfulness>()); }
5454
protected set { _productReviewHelpfulnessEntries = value; }
5555
}
5656
}

src/Libraries/SmartStore.Core/Domain/Catalog/ProductTag.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public partial class ProductTag : BaseEntity, ILocalizedEntity
2323
/// </summary>
2424
public virtual ICollection<Product> Products
2525
{
26-
get { return _products ?? (_products = new List<Product>()); }
26+
get { return _products ?? (_products = new HashSet<Product>()); }
2727
protected set { _products = value; }
2828
}
2929
}

src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public AttributeControlType AttributeControlType
8181
[DataMember]
8282
public virtual ICollection<ProductVariantAttributeValue> ProductVariantAttributeValues
8383
{
84-
get { return _productVariantAttributeValues ?? (_productVariantAttributeValues = new List<ProductVariantAttributeValue>()); }
84+
get { return _productVariantAttributeValues ?? (_productVariantAttributeValues = new HashSet<ProductVariantAttributeValue>()); }
8585
protected set { _productVariantAttributeValues = value; }
8686
}
8787

src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public partial class SpecificationAttribute : BaseEntity, ILocalizedEntity
3030
[DataMember]
3131
public virtual ICollection<SpecificationAttributeOption> SpecificationAttributeOptions
3232
{
33-
get { return _specificationAttributeOptions ?? (_specificationAttributeOptions = new List<SpecificationAttributeOption>()); }
33+
get { return _specificationAttributeOptions ?? (_specificationAttributeOptions = new HashSet<SpecificationAttributeOption>()); }
3434
protected set { _specificationAttributeOptions = value; }
3535
}
3636
}

0 commit comments

Comments
 (0)